feat: init project SelfChckout
This commit is contained in:
parent
765cc0c7cf
commit
9d31ea245c
62 changed files with 8869 additions and 7149 deletions
45
package/components/atoms/Button.tsx
Normal file
45
package/components/atoms/Button.tsx
Normal 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
|
||||
27
package/components/atoms/Input.tsx
Normal file
27
package/components/atoms/Input.tsx
Normal 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
|
||||
18
package/components/atoms/Label.tsx
Normal file
18
package/components/atoms/Label.tsx
Normal 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
|
||||
18
package/components/atoms/Title.tsx
Normal file
18
package/components/atoms/Title.tsx
Normal 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
|
||||
75
package/components/atoms/Tooltip.tsx
Normal file
75
package/components/atoms/Tooltip.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
50
package/components/layouts/AskForAffiliation.tsx
Normal file
50
package/components/layouts/AskForAffiliation.tsx
Normal 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
|
||||
110
package/components/layouts/IdentityDocumentNumber.tsx
Normal file
110
package/components/layouts/IdentityDocumentNumber.tsx
Normal 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
|
||||
52
package/components/layouts/TypeIdentityDocument.tsx
Normal file
52
package/components/layouts/TypeIdentityDocument.tsx
Normal 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
|
||||
39
package/components/molecules/FormFields.tsx
Normal file
39
package/components/molecules/FormFields.tsx
Normal 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
|
||||
20
package/components/molecules/NumericKey.tsx
Normal file
20
package/components/molecules/NumericKey.tsx
Normal 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
|
||||
69
package/components/molecules/NumericPad.tsx
Normal file
69
package/components/molecules/NumericPad.tsx
Normal 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
|
||||
28
package/components/molecules/PluEntry.tsx
Normal file
28
package/components/molecules/PluEntry.tsx
Normal 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
|
||||
13
package/components/molecules/ProductMatch.tsx
Normal file
13
package/components/molecules/ProductMatch.tsx
Normal 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
|
||||
15
package/components/molecules/Screen.tsx
Normal file
15
package/components/molecules/Screen.tsx
Normal 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
|
||||
310
package/components/organisms/ButtonPanel.tsx
Normal file
310
package/components/organisms/ButtonPanel.tsx
Normal 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
|
||||
62
package/components/organisms/Header.tsx
Normal file
62
package/components/organisms/Header.tsx
Normal 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
|
||||
65
package/components/organisms/LoginForm.tsx
Normal file
65
package/components/organisms/LoginForm.tsx
Normal 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
|
||||
33
package/components/organisms/MainPanel.tsx
Normal file
33
package/components/organisms/MainPanel.tsx
Normal 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
|
||||
47
package/components/organisms/Navbar.tsx
Normal file
47
package/components/organisms/Navbar.tsx
Normal 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;
|
||||
28
package/components/organisms/ProductList.tsx
Normal file
28
package/components/organisms/ProductList.tsx
Normal 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
|
||||
1
package/config/ApiPath.tsx
Normal file
1
package/config/ApiPath.tsx
Normal file
|
|
@ -0,0 +1 @@
|
|||
export const BASE_URL_AUTHENTICATION = "/AUTHENTICATION-SERVICE/rhi-bpc/"
|
||||
32
package/config/FetchData.tsx
Normal file
32
package/config/FetchData.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { ReturnService } from "@package/config/ReturnService"
|
||||
import i18n from "@package/utils/language/i18n"
|
||||
|
||||
const BASE_URL = process.env.NEXT_PUBLIC_API_URL
|
||||
|
||||
async function FetchData<T>(
|
||||
BASE_URL_MODULE: string,
|
||||
endpoint: string,
|
||||
options: RequestInit = {}
|
||||
): Promise<ReturnService<T>> {
|
||||
const url = `${BASE_URL}${BASE_URL_MODULE}${endpoint}`
|
||||
const text = i18n.t("errorProcessingAPI") as string
|
||||
try {
|
||||
const response = await fetch(url, options)
|
||||
|
||||
if (response.status === 403) {
|
||||
const text = i18n.t("inCorrectAccess") as string
|
||||
return new ReturnService<T>(null as unknown as T, false, text, 1)
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
return new ReturnService<T>(null as unknown as T, false, text, 1)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
return new ReturnService<T>(data as T)
|
||||
} catch (error: any) {
|
||||
return new ReturnService<T>(null as unknown as T, false, text || error.message, error.errorCode || 1)
|
||||
}
|
||||
}
|
||||
|
||||
export { FetchData }
|
||||
13
package/config/ReturnService.tsx
Normal file
13
package/config/ReturnService.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
export class ReturnService<T> {
|
||||
correct: boolean
|
||||
message: string
|
||||
errorCode: number
|
||||
object: T
|
||||
|
||||
constructor(object: T, correct = true, message = "", errorCode = 0) {
|
||||
this.correct = correct
|
||||
this.message = message
|
||||
this.errorCode = errorCode
|
||||
this.object = object
|
||||
}
|
||||
}
|
||||
29
package/styles/ThemeToggle.tsx
Normal file
29
package/styles/ThemeToggle.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
"use client"
|
||||
import React, { useEffect, useState } from "react"
|
||||
|
||||
const ThemeToggle: React.FC = () => {
|
||||
const [theme, setTheme] = useState("light")
|
||||
|
||||
useEffect(() => {
|
||||
const savedTheme = localStorage.getItem("theme")
|
||||
if (savedTheme) {
|
||||
setTheme(savedTheme)
|
||||
document.documentElement.classList.toggle("dark", savedTheme === "dark")
|
||||
}
|
||||
}, [])
|
||||
|
||||
const toggleTheme = () => {
|
||||
const newTheme = theme === "light" ? "dark" : "light"
|
||||
setTheme(newTheme)
|
||||
localStorage.setItem("theme", newTheme)
|
||||
document.documentElement.classList.toggle("dark", newTheme === "dark")
|
||||
}
|
||||
|
||||
return (
|
||||
<button onClick={toggleTheme} className="bg-primary rounded-lg p-2 text-white transition hover:bg-primary-600">
|
||||
{theme === "light" ? "Modo Oscuro" : "Modo Claro"}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export default ThemeToggle
|
||||
9
package/styles/tailwind.css
Normal file
9
package/styles/tailwind.css
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.full-size-button {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
font-size: 14px;
|
||||
}
|
||||
63
package/utils/enums/TypesDocumentsByCountry.tsx
Normal file
63
package/utils/enums/TypesDocumentsByCountry.tsx
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
export enum ColombiaDocuments {
|
||||
CEDULA_CIUDADANIA = "Cédula de Ciudadanía",
|
||||
TARJETA_IDENTIDAD = "Tarjeta de Identidad",
|
||||
PASAPORTE = "Pasaporte",
|
||||
CEDULA_EXTRANJERIA = "Cédula de Extranjería",
|
||||
}
|
||||
|
||||
export enum EcuadorDocuments {
|
||||
CEDULA_IDENTIDAD = "Cédula de Identidad",
|
||||
PASAPORTE = "Pasaporte",
|
||||
RUC = "Registro Único de Contribuyentes (RUC)",
|
||||
}
|
||||
|
||||
export enum CostaRicaDocuments {
|
||||
CEDULA_NACIONAL = "Cédula Nacional",
|
||||
DIMEX = "Documento de Identificación de Migrantes Extranjeros (DIMEX)",
|
||||
PASAPORTE = "Pasaporte",
|
||||
}
|
||||
|
||||
export enum ChileDocuments {
|
||||
CEDULA_IDENTIDAD = "Cédula de Identidad",
|
||||
PASAPORTE = "Pasaporte",
|
||||
RUT = "Rol Único Tributario (RUT)",
|
||||
}
|
||||
|
||||
export enum MexicoDocuments {
|
||||
CREDENCIAL_ELECTOR = "Credencial de Elector (INE)",
|
||||
PASAPORTE = "Pasaporte",
|
||||
CURP = "Clave Única de Registro de Población (CURP)",
|
||||
RFC = "Registro Federal de Contribuyentes (RFC)",
|
||||
}
|
||||
|
||||
export enum USADocuments {
|
||||
DRIVER_LICENSE = "Driver's License",
|
||||
PASSPORT = "Passport",
|
||||
SSN = "Social Security Number (SSN)",
|
||||
STATE_ID = "State ID",
|
||||
}
|
||||
|
||||
export enum PeruDocuments {
|
||||
DNI = "Documento Nacional de Identidad (DNI)",
|
||||
PASAPORTE = "Pasaporte",
|
||||
CARNET_EXTRANJERIA = "Carnet de Extranjería",
|
||||
}
|
||||
|
||||
export enum ArgentinaDocuments {
|
||||
DNI = "Documento Nacional de Identidad (DNI)",
|
||||
PASAPORTE = "Pasaporte",
|
||||
CUIL = "Código Único de Identificación Laboral (CUIL)",
|
||||
}
|
||||
|
||||
export enum BrazilDocuments {
|
||||
CPF = "Cadastro de Pessoas Físicas (CPF)",
|
||||
RG = "Registro Geral (RG)",
|
||||
CNH = "Carteira Nacional de Habilitação (CNH)",
|
||||
PASAPORTE = "Pasaporte",
|
||||
}
|
||||
|
||||
export enum SpainDocuments {
|
||||
DNI = "Documento Nacional de Identidad (DNI)",
|
||||
NIE = "Número de Identificación de Extranjeros (NIE)",
|
||||
PASAPORTE = "Pasaporte",
|
||||
}
|
||||
41
package/utils/getDocumentsByCountry.tsx
Normal file
41
package/utils/getDocumentsByCountry.tsx
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import {
|
||||
ArgentinaDocuments,
|
||||
BrazilDocuments,
|
||||
ChileDocuments,
|
||||
ColombiaDocuments,
|
||||
CostaRicaDocuments,
|
||||
EcuadorDocuments,
|
||||
MexicoDocuments,
|
||||
PeruDocuments,
|
||||
SpainDocuments,
|
||||
USADocuments,
|
||||
} from "@package/utils/enums/TypesDocumentsByCountry"
|
||||
|
||||
const country = process.env.NEXT_PUBLIC_STORE_COUNTRY
|
||||
|
||||
export const getDocumentsByCountry = (): string[] => {
|
||||
switch (country?.toLowerCase()) {
|
||||
case "colombia":
|
||||
return Object.values(ColombiaDocuments)
|
||||
case "ecuador":
|
||||
return Object.values(EcuadorDocuments)
|
||||
case "costarica":
|
||||
return Object.values(CostaRicaDocuments)
|
||||
case "chile":
|
||||
return Object.values(ChileDocuments)
|
||||
case "mexico":
|
||||
return Object.values(MexicoDocuments)
|
||||
case "usa":
|
||||
return Object.values(USADocuments)
|
||||
case "peru":
|
||||
return Object.values(PeruDocuments)
|
||||
case "argentina":
|
||||
return Object.values(ArgentinaDocuments)
|
||||
case "brazil":
|
||||
return Object.values(BrazilDocuments)
|
||||
case "spain":
|
||||
return Object.values(SpainDocuments)
|
||||
default:
|
||||
return []
|
||||
}
|
||||
}
|
||||
96
package/utils/language/i18n.tsx
Normal file
96
package/utils/language/i18n.tsx
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
i18n
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
fallbackLng: 'en', // Default language
|
||||
lng: 'en', // Specify the default language to use
|
||||
resources: {
|
||||
en: {
|
||||
translation: {
|
||||
lbl_wellcome: "Welcome",
|
||||
lbl_login: "Login",
|
||||
lbl_username: "Username",
|
||||
lbl_password: "Password",
|
||||
lbl_enter_PLU: "Enter PLU",
|
||||
lbl_transfer_order: "Transfer Order",
|
||||
lbl_resale: "Resale",
|
||||
lbl_add_receipt: "Add receipt",
|
||||
lbl_coupons : "Coupons",
|
||||
lbl_discount_percentage: "Discount percentage",
|
||||
lbl_amount_discount: "Amount discount",
|
||||
lbl_bag_credit: "Bag credit",
|
||||
lbl_bottle_refund: "Bottle refund",
|
||||
lbl_tax_exempt: "Tax exempt",
|
||||
lbl_item_inquiry: "Item Inquiry",
|
||||
lbl_Store: "Store",
|
||||
lbl_register: "Register",
|
||||
lbl_associate: "Associate",
|
||||
|
||||
|
||||
|
||||
msj_resume_previously_suspended_order: "Resume a previously suspended order",
|
||||
msj_transfer_Order_another_station: "Transfer an order to another station",
|
||||
msj_generate_resale: "Generate a resale",
|
||||
msj_generate_refund: "Generate a refund",
|
||||
msj_add_receipt: "Add receipt",
|
||||
msj_manage_coupons: "Manage coupons",
|
||||
msj_manage_discount_percentage: "Manage discount percentage",
|
||||
msj_manage_amount_discount: "Manage amount discount",
|
||||
msj_bag_credit_management: "Credit bag management",
|
||||
msj_bottle_refund_management: "Bottle refund management",
|
||||
msj_tax_exemption_management: "Tax exemption management",
|
||||
msj_query_search_article: "Query or search for article",
|
||||
msj_enter_your_username: "Enter your username",
|
||||
msj_enter_your_password: "Enter your password",
|
||||
msj_Incorrect_credentials_try_again: "Incorrect credentials, try again",
|
||||
},
|
||||
},
|
||||
es: {
|
||||
translation: {
|
||||
lbl_wellcome: "Bienvenido",
|
||||
lbl_login: "Iniciar sesión",
|
||||
lbl_username: "Nombre de usuario",
|
||||
lbl_password: "Contraseña",
|
||||
lbl_enter_PLU: "Ingrese PLU",
|
||||
lbl_transfer_order: "Transferir orden",
|
||||
lbl_resale: "Reventa",
|
||||
lbl_add_receipt: "Agregar recibo",
|
||||
lbl_coupons : "Cupones",
|
||||
lbl_discount_percentage: "Porcentaje de descuento",
|
||||
lbl_amount_discount: "Importe de descuento",
|
||||
lbl_bag_credit: "Bolsa de crédito",
|
||||
lbl_bottle_refund: "Devolución de botellas",
|
||||
lbl_tax_exempt: "Exento de impuestos",
|
||||
lbl_item_inquiry: "Consulta de artículo",
|
||||
lbl_Store: "Tienda",
|
||||
lbl_register: "Registro",
|
||||
lbl_associate: "Asociado",
|
||||
|
||||
|
||||
msj_resume_previously_suspended_order: "Reanuda una orden previamente suspendida",
|
||||
msj_transfer_Order_another_station: "Transfiere la orden a otra estación",
|
||||
msj_generate_resale: "Generar una reventa",
|
||||
msj_generate_refund: "Generar una devolución",
|
||||
msj_add_receipt: "Agregar recibo",
|
||||
msj_manage_coupons: "Administrar cupones",
|
||||
msj_manage_discount_percentage: "Administrar porcentaje de descuento",
|
||||
msj_manage_amount_discount: "Administrar importe de descuento",
|
||||
msj_bag_credit_management: "Gestión de bolsa de crédito",
|
||||
msj_bottle_refund_management: "Gestión de devolución de botellas",
|
||||
msj_tax_exemption_management: "Gestión de exención de impuestos",
|
||||
msj_query_search_article: "Consulta o búsqueda de artículo",
|
||||
msj_enter_your_username: "Ingrese su nombre de usuario",
|
||||
msj_enter_your_password: "Ingrese su contraseña",
|
||||
msj_Incorrect_credentials_try_again: "Credenciales incorrectas, inténtelo de nuevo",
|
||||
|
||||
},
|
||||
},
|
||||
},
|
||||
interpolation: {
|
||||
escapeValue: false, // Not needed for React as it escapes by default
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
Loading…
Add table
Add a link
Reference in a new issue