This commit is contained in:
David Arranz 2024-06-09 22:22:22 +02:00
parent a2995234ee
commit 33010c0c6b
11 changed files with 568 additions and 96 deletions

View File

@ -1,7 +1,9 @@
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { LoginPage, LogoutPage, StartPage } from "./app";
import { LoginPage, LogoutPage, SettingsPage, StartPage } from "./app";
import { CatalogList } from "./app/catalog";
import { DashboardPage } from "./app/dashboard";
import { DealersList } from "./app/dealers/list";
import { QuotesList } from "./app/quotes/list";
import { ProtectedRoute } from "./components";
export const Routes = () => {
@ -17,17 +19,41 @@ export const Routes = () => {
const routesForAuthenticatedOnly = [
{
path: "/home",
Component: DashboardPage,
element: (
<ProtectedRoute>
<DashboardPage />
</ProtectedRoute>
),
},
{
path: "/catalog",
Component: CatalogList,
},
{
path: "/profile",
element: (
<ProtectedRoute>
<h1>Profile</h1>
<CatalogList />
</ProtectedRoute>
),
},
{
path: "/dealers",
element: (
<ProtectedRoute>
<DealersList />
</ProtectedRoute>
),
},
{
path: "/quotes",
element: (
<ProtectedRoute>
<QuotesList />
</ProtectedRoute>
),
},
{
path: "/settings",
element: (
<ProtectedRoute>
<SettingsPage />
</ProtectedRoute>
),
},
@ -39,16 +65,6 @@ export const Routes = () => {
</ProtectedRoute>
),
},
{
path: "/admin",
element: <ProtectedRoute />, // Wrap the component in ProtectedRoute
children: [
{
path: "",
element: <div>Dashboard</div>,
},
],
},
];
// Define routes accessible only to non-authenticated users

View File

@ -21,7 +21,7 @@ import { useState } from "react";
import { SubmitHandler, useForm } from "react-hook-form";
import { Trans, useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import SpanishJoiMessages from "../spanish-joi-messages.json";
import SpanishJoiMessages from "../../spanish-joi-messages.json";
type LoginDataForm = ILogin_DTO;

View File

@ -0,0 +1,2 @@
export * from "./LoginPage";
export * from "./LogoutPage";

View File

@ -30,11 +30,15 @@ import { File, ListFilter, MoreHorizontal, PlusCircle } from "lucide-react";
import { Layout, LayoutContent, LayoutHeader } from "@/components";
export const CatalogList = ({ children }) => {
export const CatalogList = () => {
return (
<Layout>
<LayoutHeader />
<LayoutContent>
<div className='flex items-center'>
<h1 className='text-lg font-semibold md:text-2xl'>Catalog</h1>
</div>
<Tabs defaultValue='all'>
<div className='flex items-center'>
<TabsList>

View File

@ -1,5 +1,17 @@
import { Layout, LayoutHeader } from "@/components";
import {
ChevronLeft,
ChevronRight,
Copy,
CreditCard,
File,
ListFilter,
MoreVertical,
Truck,
} from "lucide-react";
import { Layout, LayoutContent, LayoutHeader } from "@/components";
import {
Badge,
Button,
Card,
CardContent,
@ -7,90 +19,408 @@ import {
CardFooter,
CardHeader,
CardTitle,
Input,
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
Pagination,
PaginationContent,
PaginationItem,
Progress,
Separator,
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@/ui";
import { Checkbox } from "@radix-ui/react-checkbox";
import { SyntheticEvent, useState } from "react";
import { Link } from "react-router-dom";
export const DashboardPage = () => {
const [logoutAlertVisible, setLogoutAlertVisible] = useState<boolean>(false);
const openLogoutAlert = (event: Event) => {
event.preventDefault();
setLogoutAlertVisible(true);
return;
};
const closeLogoutAlert = (event: SyntheticEvent) => {
event.preventDefault();
setLogoutAlertVisible(false);
return;
};
return (
<Layout>
<LayoutHeader />
<main className='flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:gap-8 md:p-10'>
<div className='grid w-full max-w-6xl gap-2 mx-auto'>
<h1 className='text-3xl font-semibold'>Settings</h1>
</div>
<div className='mx-auto grid w-full max-w-6xl items-start gap-6 md:grid-cols-[180px_1fr] lg:grid-cols-[250px_1fr]'>
<nav className='grid gap-4 text-sm text-muted-foreground' x-chunk='dashboard-04-chunk-0'>
<Link to='#' className='font-semibold text-primary'>
General
</Link>
<Link to='#'>Security</Link>
<Link to='#'>Integrations</Link>
<Link to='#'>Support</Link>
<Link to='#'>Organizations</Link>
<Link to='#'>Advanced</Link>
</nav>
<div className='grid gap-6'>
<Card x-chunk='dashboard-04-chunk-1'>
<CardHeader>
<CardTitle>Store Name</CardTitle>
<CardDescription>Used to identify your store in the marketplace.</CardDescription>
</CardHeader>
<CardContent>
<form>
<Input placeholder='Store Name' />
</form>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>Save</Button>
</CardFooter>
</Card>
<Card x-chunk='dashboard-04-chunk-2'>
<CardHeader>
<CardTitle>Plugins Directory</CardTitle>
<CardDescription>
The directory within your project, in which your plugins are located.
<LayoutContent className='grid items-start flex-1 gap-4 p-4 sm:px-6 sm:py-0 md:gap-8 lg:grid-cols-3 xl:grid-cols-3'>
<div className='grid items-start gap-4 auto-rows-max md:gap-8 lg:col-span-2'>
<div className='grid gap-4 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-2 xl:grid-cols-4'>
<Card className='sm:col-span-2' x-chunk='dashboard-05-chunk-0'>
<CardHeader className='pb-3'>
<CardTitle>Tus Cotizaciones</CardTitle>
<CardDescription className='max-w-lg leading-relaxed text-balance'>
Introducing Our Dynamic Orders Dashboard for Seamless Management and Insightful
Analysis.
</CardDescription>
</CardHeader>
<CardFooter>
<Button>Crear nueva cotización</Button>
</CardFooter>
</Card>
<Card x-chunk='dashboard-05-chunk-1'>
<CardHeader className='pb-2'>
<CardDescription>This Week</CardDescription>
<CardTitle className='text-4xl'>$1,329</CardTitle>
</CardHeader>
<CardContent>
<form className='flex flex-col gap-4'>
<Input placeholder='Project Name' defaultValue='/content/plugins' />
<div className='flex items-center space-x-2'>
<Checkbox id='include' defaultChecked />
<label
htmlFor='include'
className='text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
>
Allow administrators to change the directory.
</label>
</div>
</form>
<div className='text-xs text-muted-foreground'>+25% from last week</div>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>Save</Button>
<CardFooter>
<Progress value={25} aria-label='25% increase' />
</CardFooter>
</Card>
<Card x-chunk='dashboard-05-chunk-2'>
<CardHeader className='pb-2'>
<CardDescription>This Month</CardDescription>
<CardTitle className='text-4xl'>$5,329</CardTitle>
</CardHeader>
<CardContent>
<div className='text-xs text-muted-foreground'>+10% from last month</div>
</CardContent>
<CardFooter>
<Progress value={12} aria-label='12% increase' />
</CardFooter>
</Card>
</div>
<Tabs defaultValue='week'>
<div className='flex items-center'>
<TabsList>
<TabsTrigger value='week'>Week</TabsTrigger>
<TabsTrigger value='month'>Month</TabsTrigger>
<TabsTrigger value='year'>Year</TabsTrigger>
</TabsList>
<div className='flex items-center gap-2 ml-auto'>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant='outline' size='sm' className='gap-1 text-sm h-7'>
<ListFilter className='h-3.5 w-3.5' />
<span className='sr-only sm:not-sr-only'>Filter</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align='end'>
<DropdownMenuLabel>Filter by</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuCheckboxItem checked>Fulfilled</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem>Declined</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem>Refunded</DropdownMenuCheckboxItem>
</DropdownMenuContent>
</DropdownMenu>
<Button size='sm' variant='outline' className='gap-1 text-sm h-7'>
<File className='h-3.5 w-3.5' />
<span className='sr-only sm:not-sr-only'>Export</span>
</Button>
</div>
</div>
<TabsContent value='week'>
<Card x-chunk='dashboard-05-chunk-3'>
<CardHeader className='px-7'>
<CardTitle>Orders</CardTitle>
<CardDescription>Recent orders from your store.</CardDescription>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>Customer</TableHead>
<TableHead className='hidden sm:table-cell'>Type</TableHead>
<TableHead className='hidden sm:table-cell'>Status</TableHead>
<TableHead className='hidden md:table-cell'>Date</TableHead>
<TableHead className='text-right'>Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow className='bg-accent'>
<TableCell>
<div className='font-medium'>Liam Johnson</div>
<div className='hidden text-sm text-muted-foreground md:inline'>
liam@example.com
</div>
</TableCell>
<TableCell className='hidden sm:table-cell'>Sale</TableCell>
<TableCell className='hidden sm:table-cell'>
<Badge className='text-xs' variant='secondary'>
Fulfilled
</Badge>
</TableCell>
<TableCell className='hidden md:table-cell'>2023-06-23</TableCell>
<TableCell className='text-right'>$250.00</TableCell>
</TableRow>
<TableRow>
<TableCell>
<div className='font-medium'>Olivia Smith</div>
<div className='hidden text-sm text-muted-foreground md:inline'>
olivia@example.com
</div>
</TableCell>
<TableCell className='hidden sm:table-cell'>Refund</TableCell>
<TableCell className='hidden sm:table-cell'>
<Badge className='text-xs' variant='outline'>
Declined
</Badge>
</TableCell>
<TableCell className='hidden md:table-cell'>2023-06-24</TableCell>
<TableCell className='text-right'>$150.00</TableCell>
</TableRow>
<TableRow>
<TableCell>
<div className='font-medium'>Noah Williams</div>
<div className='hidden text-sm text-muted-foreground md:inline'>
noah@example.com
</div>
</TableCell>
<TableCell className='hidden sm:table-cell'>Subscription</TableCell>
<TableCell className='hidden sm:table-cell'>
<Badge className='text-xs' variant='secondary'>
Fulfilled
</Badge>
</TableCell>
<TableCell className='hidden md:table-cell'>2023-06-25</TableCell>
<TableCell className='text-right'>$350.00</TableCell>
</TableRow>
<TableRow>
<TableCell>
<div className='font-medium'>Emma Brown</div>
<div className='hidden text-sm text-muted-foreground md:inline'>
emma@example.com
</div>
</TableCell>
<TableCell className='hidden sm:table-cell'>Sale</TableCell>
<TableCell className='hidden sm:table-cell'>
<Badge className='text-xs' variant='secondary'>
Fulfilled
</Badge>
</TableCell>
<TableCell className='hidden md:table-cell'>2023-06-26</TableCell>
<TableCell className='text-right'>$450.00</TableCell>
</TableRow>
<TableRow>
<TableCell>
<div className='font-medium'>Liam Johnson</div>
<div className='hidden text-sm text-muted-foreground md:inline'>
liam@example.com
</div>
</TableCell>
<TableCell className='hidden sm:table-cell'>Sale</TableCell>
<TableCell className='hidden sm:table-cell'>
<Badge className='text-xs' variant='secondary'>
Fulfilled
</Badge>
</TableCell>
<TableCell className='hidden md:table-cell'>2023-06-23</TableCell>
<TableCell className='text-right'>$250.00</TableCell>
</TableRow>
<TableRow>
<TableCell>
<div className='font-medium'>Liam Johnson</div>
<div className='hidden text-sm text-muted-foreground md:inline'>
liam@example.com
</div>
</TableCell>
<TableCell className='hidden sm:table-cell'>Sale</TableCell>
<TableCell className='hidden sm:table-cell'>
<Badge className='text-xs' variant='secondary'>
Fulfilled
</Badge>
</TableCell>
<TableCell className='hidden md:table-cell'>2023-06-23</TableCell>
<TableCell className='text-right'>$250.00</TableCell>
</TableRow>
<TableRow>
<TableCell>
<div className='font-medium'>Olivia Smith</div>
<div className='hidden text-sm text-muted-foreground md:inline'>
olivia@example.com
</div>
</TableCell>
<TableCell className='hidden sm:table-cell'>Refund</TableCell>
<TableCell className='hidden sm:table-cell'>
<Badge className='text-xs' variant='outline'>
Declined
</Badge>
</TableCell>
<TableCell className='hidden md:table-cell'>2023-06-24</TableCell>
<TableCell className='text-right'>$150.00</TableCell>
</TableRow>
<TableRow>
<TableCell>
<div className='font-medium'>Emma Brown</div>
<div className='hidden text-sm text-muted-foreground md:inline'>
emma@example.com
</div>
</TableCell>
<TableCell className='hidden sm:table-cell'>Sale</TableCell>
<TableCell className='hidden sm:table-cell'>
<Badge className='text-xs' variant='secondary'>
Fulfilled
</Badge>
</TableCell>
<TableCell className='hidden md:table-cell'>2023-06-26</TableCell>
<TableCell className='text-right'>$450.00</TableCell>
</TableRow>
</TableBody>
</Table>
</CardContent>
</Card>
</TabsContent>
</Tabs>
</div>
</main>
<div>
<Card className='overflow-hidden' x-chunk='dashboard-05-chunk-4'>
<CardHeader className='flex flex-row items-start bg-muted/50'>
<div className='grid gap-0.5'>
<CardTitle className='flex items-center gap-2 text-lg group'>
Order Oe31b70H
<Button
size='icon'
variant='outline'
className='w-6 h-6 transition-opacity opacity-0 group-hover:opacity-100'
>
<Copy className='w-3 h-3' />
<span className='sr-only'>Copy Order ID</span>
</Button>
</CardTitle>
<CardDescription>Date: November 23, 2023</CardDescription>
</div>
<div className='flex items-center gap-1 ml-auto'>
<Button size='sm' variant='outline' className='h-8 gap-1'>
<Truck className='h-3.5 w-3.5' />
<span className='lg:sr-only xl:not-sr-only xl:whitespace-nowrap'>
Track Order
</span>
</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button size='icon' variant='outline' className='w-8 h-8'>
<MoreVertical className='h-3.5 w-3.5' />
<span className='sr-only'>More</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align='end'>
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem>Export</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>Trash</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</CardHeader>
<CardContent className='p-6 text-sm'>
<div className='grid gap-3'>
<div className='font-semibold'>Order Details</div>
<ul className='grid gap-3'>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>
Glimmer Lamps x <span>2</span>
</span>
<span>$250.00</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>
Aqua Filters x <span>1</span>
</span>
<span>$49.00</span>
</li>
</ul>
<Separator className='my-2' />
<ul className='grid gap-3'>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>Subtotal</span>
<span>$299.00</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>Shipping</span>
<span>$5.00</span>
</li>
<li className='flex items-center justify-between'>
<span className='text-muted-foreground'>Tax</span>
<span>$25.00</span>
</li>
<li className='flex items-center justify-between font-semibold'>
<span className='text-muted-foreground'>Total</span>
<span>$329.00</span>
</li>
</ul>
</div>
<Separator className='my-4' />
<div className='grid grid-cols-2 gap-4'>
<div className='grid gap-3'>
<div className='font-semibold'>Shipping Information</div>
<address className='grid gap-0.5 not-italic text-muted-foreground'>
<span>Liam Johnson</span>
<span>1234 Main St.</span>
<span>Anytown, CA 12345</span>
</address>
</div>
<div className='grid gap-3 auto-rows-max'>
<div className='font-semibold'>Billing Information</div>
<div className='text-muted-foreground'>Same as shipping address</div>
</div>
</div>
<Separator className='my-4' />
<div className='grid gap-3'>
<div className='font-semibold'>Customer Information</div>
<dl className='grid gap-3'>
<div className='flex items-center justify-between'>
<dt className='text-muted-foreground'>Customer</dt>
<dd>Liam Johnson</dd>
</div>
<div className='flex items-center justify-between'>
<dt className='text-muted-foreground'>Email</dt>
<dd>
<a href='mailto:'>liam@acme.com</a>
</dd>
</div>
<div className='flex items-center justify-between'>
<dt className='text-muted-foreground'>Phone</dt>
<dd>
<a href='tel:'>+1 234 567 890</a>
</dd>
</div>
</dl>
</div>
<Separator className='my-4' />
<div className='grid gap-3'>
<div className='font-semibold'>Payment Information</div>
<dl className='grid gap-3'>
<div className='flex items-center justify-between'>
<dt className='flex items-center gap-1 text-muted-foreground'>
<CreditCard className='w-4 h-4' />
Visa
</dt>
<dd>**** **** **** 4532</dd>
</div>
</dl>
</div>
</CardContent>
<CardFooter className='flex flex-row items-center px-6 py-3 border-t bg-muted/50'>
<div className='text-xs text-muted-foreground'>
Updated <time dateTime='2023-11-23'>November 23, 2023</time>
</div>
<Pagination className='w-auto ml-auto mr-0'>
<PaginationContent>
<PaginationItem>
<Button size='icon' variant='outline' className='w-6 h-6'>
<ChevronLeft className='h-3.5 w-3.5' />
<span className='sr-only'>Previous Order</span>
</Button>
</PaginationItem>
<PaginationItem>
<Button size='icon' variant='outline' className='w-6 h-6'>
<ChevronRight className='h-3.5 w-3.5' />
<span className='sr-only'>Next Order</span>
</Button>
</PaginationItem>
</PaginationContent>
</Pagination>
</CardFooter>
</Card>
</div>
</LayoutContent>
</Layout>
);
};

View File

@ -0,0 +1,14 @@
import { Layout, LayoutContent, LayoutHeader } from "@/components";
export const DealersList = () => {
return (
<Layout>
<LayoutHeader />
<LayoutContent>
<div className='flex items-center'>
<h1 className='text-lg font-semibold md:text-2xl'>Dealers</h1>
</div>
</LayoutContent>
</Layout>
);
};

View File

@ -1,8 +1,8 @@
export * from "./ErrorPage";
export * from "./LoginPage";
export * from "./LogoutPage";
export * from "./StartPage";
export * from "./auth";
export * from "./catalog";
export * from "./dashboard";
//export * from "./dealers";
//export * from "./quotes";
export * from "./dealers";
export * from "./quotes";
export * from "./settings";

View File

@ -0,0 +1,14 @@
import { Layout, LayoutContent, LayoutHeader } from "@/components";
export const QuotesList = () => {
return (
<Layout>
<LayoutHeader />
<LayoutContent>
<div className='flex items-center'>
<h1 className='text-lg font-semibold md:text-2xl'>Quotes</h1>
</div>
</LayoutContent>
</Layout>
);
};

View File

@ -0,0 +1,81 @@
import { Layout, LayoutHeader } from "@/components";
import {
Button,
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
Input,
} from "@/ui";
import { Checkbox } from "@radix-ui/react-checkbox";
import { Link } from "react-router-dom";
export const SettingsPage = () => {
return (
<Layout>
<LayoutHeader />
<main className='flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:gap-8 md:p-10'>
<div className='grid w-full max-w-6xl gap-2 mx-auto'>
<h1 className='text-3xl font-semibold'>Settings</h1>
</div>
<div className='mx-auto grid w-full max-w-6xl items-start gap-6 md:grid-cols-[180px_1fr] lg:grid-cols-[250px_1fr]'>
<nav className='grid gap-4 text-sm text-muted-foreground' x-chunk='dashboard-04-chunk-0'>
<Link to='#' className='font-semibold text-primary'>
General
</Link>
<Link to='#'>Security</Link>
<Link to='#'>Integrations</Link>
<Link to='#'>Support</Link>
<Link to='#'>Organizations</Link>
<Link to='#'>Advanced</Link>
</nav>
<div className='grid gap-6'>
<Card x-chunk='dashboard-04-chunk-1'>
<CardHeader>
<CardTitle>Store Name</CardTitle>
<CardDescription>Used to identify your store in the marketplace.</CardDescription>
</CardHeader>
<CardContent>
<form>
<Input placeholder='Store Name' />
</form>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>Save</Button>
</CardFooter>
</Card>
<Card x-chunk='dashboard-04-chunk-2'>
<CardHeader>
<CardTitle>Plugins Directory</CardTitle>
<CardDescription>
The directory within your project, in which your plugins are located.
</CardDescription>
</CardHeader>
<CardContent>
<form className='flex flex-col gap-4'>
<Input placeholder='Project Name' defaultValue='/content/plugins' />
<div className='flex items-center space-x-2'>
<Checkbox id='include' defaultChecked />
<label
htmlFor='include'
className='text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
>
Allow administrators to change the directory.
</label>
</div>
</form>
</CardContent>
<CardFooter className='px-6 py-4 border-t'>
<Button>Save</Button>
</CardFooter>
</Card>
</div>
</div>
</main>
</Layout>
);
};

View File

@ -1,8 +1,19 @@
import { cn } from "@/lib/utils";
import { PropsWithChildren } from "react";
export const LayoutContent = ({ children }: PropsWithChildren) => {
export const LayoutContent = ({
className,
children,
}: PropsWithChildren<{
className?: string;
}>) => {
return (
<main className='flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:gap-8 md:p-10'>
<main
className={cn(
"flex min-h-[calc(100vh_-_theme(spacing.16))] flex-1 flex-col gap-4 bg-muted/40 p-4 md:gap-8 md:p-10",
className
)}
>
{children}
</main>
);