feat: init project SelfChckout

This commit is contained in:
Luis Felipe Cadavid 2024-09-19 19:22:43 -05:00
parent 765cc0c7cf
commit 9d31ea245c
62 changed files with 8869 additions and 7149 deletions

View file

@ -0,0 +1,45 @@
"use client"
import { Button as MUIButton } from "@mui/material"
import React from "react"
interface ButtonProps {
label: string
variant?: "primary" | "secondary" | "success" | "danger" | "warning" | "info"
onClick?: () => void
disabled?: boolean
className?: string
startIcon?: React.ReactNode
}
const Button: React.FC<ButtonProps> = ({
label,
variant = "primary",
onClick,
disabled,
className = "",
startIcon,
}) => {
const colorMap: Record<string, "primary" | "secondary" | "error" | "warning" | "info" | "success"> = {
primary: "primary",
secondary: "secondary",
success: "success",
danger: "error",
warning: "warning",
info: "info",
}
return (
<MUIButton
onClick={onClick}
disabled={disabled}
color={colorMap[variant ?? "primary"]}
className={className}
variant="contained"
startIcon={startIcon}
>
{label}
</MUIButton>
)
}
export default Button

View file

@ -0,0 +1,27 @@
"use client"
import { TextField } from "@mui/material"
import React from "react"
interface InputProps {
type: string
placeholder?: string
value: string
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
autocomplete?: string
}
const Input: React.FC<InputProps> = ({ type, placeholder, value, onChange, autocomplete }) => {
return (
<TextField
type={type}
placeholder={placeholder}
value={value}
onChange={onChange}
autoComplete={autocomplete}
fullWidth
variant="outlined"
/>
)
}
export default Input

View file

@ -0,0 +1,18 @@
"use client"
import { Typography } from "@mui/material"
import React from "react"
interface LabelProps {
htmlFor: string
text: string
}
const Label: React.FC<LabelProps> = ({ htmlFor, text }) => {
return (
<Typography variant="subtitle1" component="label" htmlFor={htmlFor} className="mb-2 block">
{text}
</Typography>
)
}
export default Label

View file

@ -0,0 +1,18 @@
"use client"
import { Typography } from "@mui/material"
import React from "react"
interface TitleProps {
text: string
size?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6"
}
const Title: React.FC<TitleProps> = ({ text, size = "h1" }) => {
return (
<Typography variant={size} className="font-bold">
{text}
</Typography>
)
}
export default Title

View file

@ -0,0 +1,75 @@
"use client"
import * as RadixTooltip from "@radix-ui/react-tooltip"
import { cva, VariantProps } from "class-variance-authority"
import React from "react"
import { twMerge } from "tailwind-merge"
const tooltipContent = cva([], {
variants: {
intent: {
primary: ["rounded-0.5md", "bg-zinc-700", "font-open-sans", "text-white"],
},
size: {
md: ["px-4", "py-2.5", "text-2xs"],
},
},
defaultVariants: {
intent: "primary",
size: "md",
},
})
const tooltipArrow = cva([], {
variants: {
intent: {
primary: ["fill-zinc-700"],
},
size: {
md: ["w-4", "h-2"],
},
},
defaultVariants: {
intent: "primary",
size: "md",
},
})
export interface TooltipProps extends VariantProps<typeof tooltipContent>, RadixTooltip.TooltipProps {
explainer: React.ReactElement | string
children: React.ReactElement
className?: string
withArrow?: boolean
side?: "top" | "right" | "bottom" | "left"
}
export function Tooltip({
children,
explainer,
open,
defaultOpen,
onOpenChange,
intent,
size,
side = "top",
className,
withArrow,
}: TooltipProps) {
return (
<RadixTooltip.Provider>
<RadixTooltip.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange} delayDuration={200}>
<RadixTooltip.Trigger asChild>{children}</RadixTooltip.Trigger>
<RadixTooltip.Portal>
<RadixTooltip.Content
side={side}
sideOffset={5}
className={twMerge(tooltipContent({ intent, size, className }))}
>
{explainer}
{withArrow ? <RadixTooltip.Arrow className={twMerge(tooltipArrow({ intent, size, className }))} /> : null}
</RadixTooltip.Content>
</RadixTooltip.Portal>
</RadixTooltip.Root>
</RadixTooltip.Provider>
)
}

View file

@ -0,0 +1,50 @@
"use client"
import { Box, Card, CardContent } from "@mui/material"
import Grid from "@mui/material/Grid2"
import Button from "@atoms/Button"
import Label from "@atoms/Label"
import Title from "@atoms/Title"
interface AskForAffiliationProps {
onAffiliationSelect: (isAffiliated: boolean) => void
}
const AskForAffiliation: React.FC<AskForAffiliationProps> = ({ onAffiliationSelect }) => {
const handleYesClick = () => {
onAffiliationSelect(true)
}
const handleNoClick = () => {
onAffiliationSelect(false)
}
return (
<Card sx={{ width: "100%", maxWidth: "100%" }}>
<CardContent>
<Box
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
height: "100%",
p: 2,
}}
>
<Title text="Se requiere Información" size="h3" />
<Label htmlFor="loyalty" text="¿Está registrado como afiliado?" />
<Box sx={{ mt: 3, display: "flex", gap: 3 }}>
<Grid size={{ xs: 6 }} sx={{ minWidth: "200px" }}>
<Button label="Sí" onClick={handleYesClick} variant="primary" className="h-16 w-full" />
</Grid>
<Grid size={{ xs: 6 }} sx={{ minWidth: "200px" }}>
<Button label="No" onClick={handleNoClick} variant="primary" className="h-16 w-full" />
</Grid>
</Box>
</Box>
</CardContent>
</Card>
)
}
export default AskForAffiliation

View file

@ -0,0 +1,110 @@
"use client"
import { Box, Card, CardContent } from "@mui/material"
import Grid from "@mui/material/Grid2"
import React, { useEffect, useState } from "react"
import Button from "@atoms/Button"
import Input from "@atoms/Input"
import Title from "@atoms/Title"
interface IdentityDocumentNumberProps {
documentType: string
onSubmit: (documentNumber: string) => void
}
const IdentityDocumentNumber: React.FC<IdentityDocumentNumberProps> = ({ documentType, onSubmit }) => {
const [inputValue, setInputValue] = useState<string>("")
const [keyboardMode, setKeyboardMode] = useState<"numeric" | "alpha">("numeric")
const [isAlphaEnabled, setIsAlphaEnabled] = useState<boolean>(false)
useEffect(() => {
const alphaDocuments = ["PASAPORTE", "CURP", "RFC", "NIE", "RUT"] // Documentos que contienen letras
setIsAlphaEnabled(alphaDocuments.includes(documentType.toUpperCase()))
setKeyboardMode(isAlphaEnabled ? "alpha" : "numeric")
}, [documentType, isAlphaEnabled])
const handleKeyPress = (key: string) => {
setInputValue((prev) => prev + key)
}
const handleDelete = () => {
setInputValue((prev) => prev.slice(0, -1))
}
// Renderiza el teclado basado en el modo seleccionado
const renderKeyboard = () => {
if (keyboardMode === "numeric") {
return (
<>
{["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"].map((num) => (
<Grid key={num} size={{ xs: 4 }}>
<Button label={num} onClick={() => handleKeyPress(num)} variant="primary" className="h-16 w-full" />
</Grid>
))}
</>
)
} else {
return (
<>
{"ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("").map((letter) => (
<Grid key={letter} size={{ xs: 2 }}>
<Button label={letter} onClick={() => handleKeyPress(letter)} variant="primary" className="h-16 w-full" />
</Grid>
))}
</>
)
}
}
return (
<Card sx={{ width: "100%", maxWidth: "100%" }}>
<CardContent>
<Box
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
height: "100%",
p: 2,
}}
>
{/* Título */}
<Title text={`Ingrese el número de ${documentType}`} size="h4" />
{/* Input que muestra el valor actual */}
<Input
type="text"
placeholder="Ingrese el número de documento"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<Grid container spacing={2} justifyContent="center" alignItems="center" sx={{ mt: 3 }}>
<Grid size={{ xs: 4 }}>
<Button label="Borrar" onClick={handleDelete} variant="danger" className="h-16 w-full" />
</Grid>
<Grid size={{ xs: 4 }}>
<Button label="Cancelar" onClick={() => setInputValue("")} variant="danger" className="h-16 w-full" />
</Grid>
{renderKeyboard()}
<Grid size={{ xs: 4 }}>
<Button label="Ingresar" onClick={() => onSubmit(inputValue)} variant="success" className="h-16 w-full" />
</Grid>
{isAlphaEnabled && (
<Grid size={{ xs: 4 }}>
<Button
label={`Cambiar a ${keyboardMode === "numeric" ? "Alfabético" : "Numérico"}`}
onClick={() => setKeyboardMode(keyboardMode === "numeric" ? "alpha" : "numeric")}
variant="secondary"
className="h-16 w-full"
/>
</Grid>
)}
</Grid>
</Box>
</CardContent>
</Card>
)
}
export default IdentityDocumentNumber

View file

@ -0,0 +1,52 @@
"use client"
import { Box, Card, CardContent } from "@mui/material"
import Grid from "@mui/material/Grid2"
import Button from "@atoms/Button"
import Label from "@atoms/Label"
import Title from "@atoms/Title"
interface TypesDocumentProps {
typesDocument: string[]
onDocumentSelect: (documentType: string) => void
}
const TypeIdentityDocument: React.FC<TypesDocumentProps> = ({ typesDocument, onDocumentSelect }) => {
const handleDocumentClick = (documentType: string) => {
onDocumentSelect(documentType)
}
return (
<Card sx={{ width: "100%", maxWidth: "100%" }}>
<CardContent>
<Box
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
height: "100%",
p: 2,
}}
>
<Title text="Se requiere Información" size="h4" />
<Label htmlFor="loyalty" text="Seleccione el tipo de documento de identidad" />
<Grid container spacing={2} justifyContent="center" sx={{ mt: 3 }}>
{typesDocument.map((documentType, index) => (
<Grid key={index} size={{ xs: 6, md: 4 }} sx={{ minWidth: "200px" }}>
<Button
label={documentType}
onClick={() => handleDocumentClick(documentType)}
variant="primary"
className="h-16 w-full"
/>
</Grid>
))}
</Grid>
</Box>
</CardContent>
</Card>
)
}
export default TypeIdentityDocument

View file

@ -0,0 +1,39 @@
import { Box, FormControl } from "@mui/material"
import React from "react"
import Input from "@atoms/Input"
import Label from "@atoms/Label"
interface FormFieldProps {
label: string
inputType: string
inputValue: string
onInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void
placeholder?: string
autocomplete?: string
}
const FormField: React.FC<FormFieldProps> = ({
label,
inputType,
inputValue,
onInputChange,
placeholder,
autocomplete,
}) => {
return (
<Box mb={2}>
<FormControl fullWidth>
<Label htmlFor={label} text={label} />
<Input
type={inputType}
value={inputValue}
onChange={onInputChange}
placeholder={placeholder}
autocomplete={autocomplete}
/>
</FormControl>
</Box>
)
}
export default FormField

View file

@ -0,0 +1,20 @@
"use client"
import Grid2 from "@mui/material/Grid2"
import React from "react"
import Button from "@atoms/Button"
interface NumericKeyProps {
label: string | number
onClick: () => void
className?: string
}
const NumericKey: React.FC<NumericKeyProps> = ({ label, onClick, className }) => {
return (
<Grid2 container justifyContent="center" component="div">
<Button label={label.toString()} onClick={onClick} className={`h-16 w-full ${className}`} />
</Grid2>
)
}
export default NumericKey

View file

@ -0,0 +1,69 @@
"use client"
import Grid from "@mui/material/Grid2"
import React from "react"
import NumericKey from "@molecules/NumericKey"
const NumericPad: React.FC = () => {
const handleKeyClick = (key: number) => {
console.log(`Key pressed: ${key}`)
}
return (
<Grid container spacing={0.4} justifyContent="center" alignItems="center">
<Grid size={{ xs: 6 }}>
<NumericKey
label="Cancel"
onClick={() => console.log("Cancel pressed")}
className="h-12 w-full bg-danger-light text-white hover:bg-danger-dark"
/>
</Grid>
<Grid size={{ xs: 6 }}>
<NumericKey label="clear" onClick={() => console.log("Clear pressed")} className="size-12 bg-secondary-light" />
</Grid>
<Grid size={{ xs: 3 }} sx={{ minWidth: "100px" }}>
<NumericKey
label="0"
onClick={() => console.log("0")}
className="size-24 bg-primary-500 text-white hover:bg-primary-600"
/>
</Grid>
{[...Array(9).keys()].map((i) => (
<Grid key={i + 1} size={{ xs: 3 }} sx={{ minWidth: "100px" }}>
{" "}
<NumericKey
label={i + 1}
onClick={() => handleKeyClick(i + 1)}
className="size-24 bg-primary-500 text-white hover:bg-primary-600"
/>
</Grid>
))}
<Grid size={{ xs: 3 }} sx={{ minWidth: "100px" }}>
<NumericKey
label="."
onClick={() => console.log(".")}
className="size-24 bg-primary-500 text-white hover:bg-primary-600"
/>
</Grid>
<Grid size={{ xs: 3 }} sx={{ minWidth: "100px" }}>
<NumericKey label="/" onClick={() => console.log("Divide pressed")} className="size-12 bg-secondary-light" />
</Grid>
<Grid size={{ xs: 3 }} sx={{ minWidth: "100px" }}>
<NumericKey label="QTY" onClick={() => console.log("QTY pressed")} className="size-12 bg-secondary-light" />
</Grid>
<Grid size={{ xs: 3 }} sx={{ minWidth: "100px" }}>
<NumericKey label="Price" onClick={() => console.log("Price pressed")} className="size-12 bg-secondary-light" />
</Grid>
<Grid size={{ xs: 6 }}>
<NumericKey
label="Enter"
onClick={() => console.log("Enter pressed")}
className="h-12 w-full bg-success-light text-white hover:bg-success-dark"
/>
</Grid>
</Grid>
)
}
export default NumericPad

View file

@ -0,0 +1,28 @@
"use client"
import { Box } from "@mui/material"
import React, { useState } from "react"
import { useTranslation } from "react-i18next"
import Input from "@atoms/Input"
const PluEntry: React.FC = () => {
const [plu, setPlu] = useState("")
const { t } = useTranslation()
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setPlu(e.target.value)
}
return (
<Box sx={{ p: 1, backgroundColor: "#f5f5f5", borderRadius: 2 }}>
<Input
type="text"
value={plu}
onChange={handleInputChange}
placeholder={t("lbl_enter_PLU")}
autocomplete="off"
/>
</Box>
)
}
export default PluEntry

View file

@ -0,0 +1,13 @@
"use client"
import { Box, Typography } from "@mui/material"
import React from "react"
const ProductMatch: React.FC = () => {
return (
<Box sx={{ p: 2, backgroundColor: "#f5f5f5", borderRadius: 1 }}>
<Typography variant="h6">Coincidencia de productos:</Typography> {/* TODO: Aquí irán los productos que coincidan con el PLU */}
</Box>
)
}
export default ProductMatch

View file

@ -0,0 +1,15 @@
"use client"
import { Box, Typography } from "@mui/material"
import React from "react"
const Screen: React.FC = () => {
return (
<Box sx={{ p: 2, backgroundColor: "#f5f5f5", borderRadius: 1, textAlign: "center" }}>{/* TODO: Logica para valores */}
<Typography variant="h6">Item Subtotal: $0.00</Typography>
<Typography variant="body1">Total Savings: $0.00</Typography>
<Typography variant="body1">Tax: $0.00</Typography>
</Box>
)
}
export default Screen

View file

@ -0,0 +1,310 @@
import AccountBalanceWalletIcon from "@mui/icons-material/AccountBalanceWallet"
import BackspaceIcon from "@mui/icons-material/Backspace"
import CreditCardIcon from "@mui/icons-material/CreditCard"
import DeleteIcon from "@mui/icons-material/Delete"
import DiscountIcon from "@mui/icons-material/Discount"
import LockIcon from "@mui/icons-material/Lock"
import PercentIcon from "@mui/icons-material/Percent"
import PlayArrowIcon from "@mui/icons-material/PlayArrow"
import ReceiptIcon from "@mui/icons-material/Receipt"
import RedeemIcon from "@mui/icons-material/Redeem"
import ReplayIcon from "@mui/icons-material/Replay"
import SearchIcon from "@mui/icons-material/Search"
import SettingsIcon from "@mui/icons-material/Settings"
import ShoppingBagIcon from "@mui/icons-material/ShoppingBag"
import ShoppingBasketIcon from "@mui/icons-material/ShoppingBasket"
import ShoppingCartIcon from "@mui/icons-material/ShoppingCart"
import StorefrontIcon from "@mui/icons-material/Storefront"
import TransferWithinAStationIcon from "@mui/icons-material/TransferWithinAStation"
import { Box, Card, CardContent } from "@mui/material"
import Grid from "@mui/material/Grid2"
import React from "react"
import { useTranslation } from "react-i18next"
import Button from "@atoms/Button"
import { Tooltip } from "@atoms/Tooltip"
import ThemeToggle from "@styles/ThemeToggle"
const ButtonPanel: React.FC = () => {
const { t } = useTranslation()
return (
<Card sx={{ height: "100%" }}>
<CardContent>
<ThemeToggle />
<Grid container spacing={1}>
<Grid size={{ xs: 4 }}>
<Tooltip explainer="Anula la orden actual" side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label="Void Order"
onClick={() => {}}
variant="danger"
className="full-size-button"
startIcon={<ShoppingCartIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer="Void Last" side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label="Void Last"
onClick={() => {}}
variant="danger"
className="full-size-button"
startIcon={<BackspaceIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_resume_previously_suspended_order")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label="Resume"
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<PlayArrowIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_transfer_Order_another_station")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("lbl_transfer_order")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<TransferWithinAStationIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_generate_resale")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("lbl_resale")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<StorefrontIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_generate_refund")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("lbl_returns")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<ReplayIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_add_receipt")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("lbl_add_receipt")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<ReceiptIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_manage_coupons")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("lbl_coupons")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<RedeemIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_manage_discount_percentage")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("lbl_discount_percentage")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<PercentIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_manage_amount_discount")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("lbl_amount_discount")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<DiscountIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("lbl_bag_fee")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("msj_bag_fee")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<ShoppingBagIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_bag_credit_management")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("lbl_bag_credit")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<ShoppingBasketIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_bottle_refund_management")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("lbl_bottle_refund")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<DeleteIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_tax_exemption_management")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("lbl_tax_exempt")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<CreditCardIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_delete_tax_exception")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("lbl_clear_exempt")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<CreditCardIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 4 }}>
<Tooltip explainer={t("msj_query_search_article")} side="top" withArrow>
<Box sx={{ width: "100%" }}>
<Button
label={t("lbl_item_inquiry")}
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<SearchIcon />}
/>
</Box>
</Tooltip>
</Grid>
<Grid size={{ xs: 12 }} container spacing={1} justifyContent="center">
<Grid size={{ xs: 4 }}>
<Box sx={{ width: "100%" }}>
<Button
label=""
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<SettingsIcon />}
/>
</Box>
</Grid>
<Grid size={{ xs: 4 }}>
<Box sx={{ width: "100%" }}>
<Button
label=""
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<AccountBalanceWalletIcon />}
/>
</Box>
</Grid>
<Grid size={{ xs: 4 }}>
<Box sx={{ width: "100%" }}>
<Button
label=""
onClick={() => {}}
variant="primary"
className="full-size-button"
startIcon={<SearchIcon />}
/>
</Box>
</Grid>
</Grid>
<Grid size={{ xs: 12 }}>
<Box sx={{ width: "100%" }}>
<Button
label=""
onClick={() => {}}
variant="warning"
className="full-size-button"
startIcon={<LockIcon />}
/>
</Box>
</Grid>
</Grid>
</CardContent>
</Card>
)
}
export default ButtonPanel

View file

@ -0,0 +1,62 @@
import MoreVertIcon from "@mui/icons-material/MoreVert"
import PersonIcon from "@mui/icons-material/Person"
import { Card, CardContent, CardHeader, IconButton, Typography } from "@mui/material"
import Grid from "@mui/material/Grid2"
import React from "react"
import { useTranslation } from "react-i18next"
interface HeaderProps {
sx?: object
}
const Header: React.FC<HeaderProps> = ({ sx }) => {
const { t } = useTranslation()
return (
<Card sx={{ ...sx, p: 0.1 }}>
<CardHeader
title="Generic userd"
subheader="Add Member"
titleTypographyProps={{ color: "text.primary", fontWeight: "bold", fontSize: "1rem" }}
subheaderTypographyProps={{ color: "text.secondary", fontSize: "0.75rem" }}
sx={{ paddingBottom: 0 }}
/>
<CardContent sx={{ paddingTop: 0.2 }}>
<Grid container alignItems="center" justifyContent="space-between">
<Grid>
<Typography variant="body2" color="text.secondary">
Fri, 13 Sept
</Typography>
</Grid>
<Grid>
<Typography variant="body2" color="text.secondary">
9:36 am
</Typography>
</Grid>
<Grid>
<Typography variant="body2" color="text.secondary">
{t('lbl_Store')}: <strong>8004</strong>
</Typography>
</Grid>
<Grid>
<Typography variant="body2" color="text.secondary">
{t('lbl_register')}: <strong>317</strong>
</Typography>
</Grid>
<Grid container alignItems="center">
<PersonIcon sx={{ color: "text.secondary", fontSize: "18px", mr: 0.9 }} /> {/* Icono más pequeño */}
<Typography variant="body2" color="text.secondary">
{t('lbl_associate')} <strong>2</strong>
</Typography>
</Grid>
<Grid>
<IconButton size="small">
<MoreVertIcon color="action" sx={{ fontSize: "18px" }} />
</IconButton>
</Grid>
</Grid>
</CardContent>
</Card>
)
}
export default Header

View file

@ -0,0 +1,65 @@
"use client"
import { Box, Typography } from "@mui/material"
import { useRouter } from "next/navigation"
import React, { useState } from "react"
import { useTranslation } from "react-i18next"
import { auth } from "@app/account/controller/AuthController"
import Button from "@atoms/Button"
import Input from "@atoms/Input"
import Label from "@atoms/Label"
const LoginForm: React.FC = () => {
const [username, setUsername] = useState("")
const [password, setPassword] = useState("")
const [error, setError] = useState<string | null>(null)
const router = useRouter()
const { t } = useTranslation()
const handleLogin = async () => {
const token = await auth(username, password)
if (token) {
router.push("/home")
} else {
setError( t("msj_Incorrect_credentials_try_again."))
}
}
return (
<Box
component="form"
onSubmit={(e) => {
e.preventDefault()
handleLogin()
}}
sx={{ display: "flex", flexDirection: "column", gap: 3, width: "100%" }}
>
<Box>
<Label htmlFor={t("lbl_username")} text={t("lbl_username")} />
<Input
type="text"
placeholder={t("msj_enter_your_username")}
value={username}
onChange={(e) => setUsername(e.target.value)}
autocomplete="username"
/>
</Box>
<Box>
<Label htmlFor={t("lbl_password")} text={t("lbl_password")} />
<Input
type="password"
placeholder={t("msj_enter_your_password")}
value={password}
onChange={(e) => setPassword(e.target.value)}
autocomplete="current-password"
/>
</Box>
{error && <Typography color="error">{error}</Typography>}
<Button label={t("lbl_login")} onClick={handleLogin} variant="primary" />
</Box>
)
}
export default LoginForm

View file

@ -0,0 +1,33 @@
"use client"
import { Card, CardContent } from "@mui/material"
import Grid from "@mui/material/Grid2"
import React from "react"
import NumericPad from "@molecules/NumericPad"
import PluEntry from "@molecules/PluEntry"
import ProductMatch from "@molecules/ProductMatch"
import Screen from "@molecules/Screen"
const MainPanel: React.FC = () => {
return (
<Card sx={{ height: "100%" }}>
<CardContent sx={{ padding: "8px" }}>
<Grid container spacing={1} justifyContent="center" alignItems="stretch">
<Grid size={{ xs: 12 }}>
<Screen />
</Grid>
<Grid size={{ xs: 12 }}>
<ProductMatch />
</Grid>
<Grid size={{ xs: 12 }}>
<PluEntry />
</Grid>
<Grid size={{ xs: 12 }}>
<NumericPad />
</Grid>
</Grid>
</CardContent>
</Card>
)
}
export default MainPanel

View file

@ -0,0 +1,47 @@
"use client";
import Grid from '@mui/material/Grid2';
import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import i18n from '@package/utils/language/i18n';
const Navbar: React.FC = () => {
const { t } = useTranslation();
const [language, setLanguage] = useState(i18n.language || 'en');
const changeLanguage = (lng: string) => {
i18n.changeLanguage(lng);
setLanguage(lng);
};
useEffect(() => {
setLanguage(i18n.language);
}, []);
return (
<Grid
container
justifyContent="space-between"
alignItems="center"
className="bg-blue-600 text-white p-4"
>
<Grid>
<h1 className="text-white font-bold">{t('lbl_wellcome')}</h1>
</Grid>
<Grid>
<Select
value={language}
onChange={(e) => changeLanguage(e.target.value as string)}
variant="outlined"
className="bg-white text-black"
>
<MenuItem value="en">English</MenuItem>
<MenuItem value="es">Español</MenuItem>
</Select>
</Grid>
</Grid>
);
};
export default Navbar;

View file

@ -0,0 +1,28 @@
"use client"
import { Card, CardContent, Typography } from "@mui/material"
import React from "react"
const ProductList: React.FC = () => {
return (
<Card sx={{ height: "100%" }}>
{" "}
{/* Ajustar la altura de la Card */}
<CardContent>
<Typography variant="h6" color="text.primary">
Lista de productos
</Typography>
<Typography variant="body1" color="text.secondary">
Producto 1
</Typography>
<Typography variant="body1" color="text.secondary">
Producto 2
</Typography>
<Typography variant="body1" color="text.secondary">
Producto 3
</Typography>
</CardContent>
</Card>
)
}
export default ProductList