diff --git a/ventaboletos/package-lock.json b/ventaboletos/package-lock.json index 0169161..3f76544 100644 --- a/ventaboletos/package-lock.json +++ b/ventaboletos/package-lock.json @@ -9,8 +9,10 @@ "version": "0.1.0", "dependencies": { "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-label": "^2.1.2", "@radix-ui/react-select": "^2.1.6", "@radix-ui/react-slot": "^1.1.2", + "@radix-ui/react-tabs": "^1.1.3", "@supabase/ssr": "^0.5.2", "@supabase/supabase-js": "^2.49.1", "class-variance-authority": "^0.7.1", @@ -1065,6 +1067,28 @@ } } }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.2.tgz", + "integrity": "sha512-zo1uGMTaNlHehDyFQcDZXRJhUPDuukcnHz0/jnrup0JA6qL+AFpAnty+7VKa9esuU5xTblAZzTGYJKSKaBxBhw==", + "dependencies": { + "@radix-ui/react-primitive": "2.0.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz", @@ -1164,6 +1188,36 @@ } } }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz", + "integrity": "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-collection": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-select": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.6.tgz", @@ -1223,6 +1277,35 @@ } } }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.3.tgz", + "integrity": "sha512-9mFyI30cuRDImbmFF6O2KUJdgEOsGh9Vmx9x/Dh9tOhL7BngmQPQfwW4aejKm5OHpfWIdmeV6ySyuxoOGjtNng==", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-direction": "1.1.0", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-roving-focus": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", diff --git a/ventaboletos/package.json b/ventaboletos/package.json index cdb6117..db9137e 100644 --- a/ventaboletos/package.json +++ b/ventaboletos/package.json @@ -10,8 +10,10 @@ }, "dependencies": { "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-label": "^2.1.2", "@radix-ui/react-select": "^2.1.6", "@radix-ui/react-slot": "^1.1.2", + "@radix-ui/react-tabs": "^1.1.3", "@supabase/ssr": "^0.5.2", "@supabase/supabase-js": "^2.49.1", "class-variance-authority": "^0.7.1", diff --git a/ventaboletos/src/components/ui/input.jsx b/ventaboletos/src/components/ui/input.jsx new file mode 100644 index 0000000..41ec05e --- /dev/null +++ b/ventaboletos/src/components/ui/input.jsx @@ -0,0 +1,19 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Input = React.forwardRef(({ className, type, ...props }, ref) => { + return ( + (<input + type={type} + className={cn( + "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", + className + )} + ref={ref} + {...props} />) + ); +}) +Input.displayName = "Input" + +export { Input } diff --git a/ventaboletos/src/components/ui/label.jsx b/ventaboletos/src/components/ui/label.jsx new file mode 100644 index 0000000..a1f4099 --- /dev/null +++ b/ventaboletos/src/components/ui/label.jsx @@ -0,0 +1,16 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { cva } from "class-variance-authority"; + +import { cn } from "@/lib/utils" + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" +) + +const Label = React.forwardRef(({ className, ...props }, ref) => ( + <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} /> +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/ventaboletos/src/components/ui/tabs.jsx b/ventaboletos/src/components/ui/tabs.jsx new file mode 100644 index 0000000..b674eb9 --- /dev/null +++ b/ventaboletos/src/components/ui/tabs.jsx @@ -0,0 +1,41 @@ +import * as React from "react" +import * as TabsPrimitive from "@radix-ui/react-tabs" + +import { cn } from "@/lib/utils" + +const Tabs = TabsPrimitive.Root + +const TabsList = React.forwardRef(({ className, ...props }, ref) => ( + <TabsPrimitive.List + ref={ref} + className={cn( + "inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground", + className + )} + {...props} /> +)) +TabsList.displayName = TabsPrimitive.List.displayName + +const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => ( + <TabsPrimitive.Trigger + ref={ref} + className={cn( + "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow", + className + )} + {...props} /> +)) +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName + +const TabsContent = React.forwardRef(({ className, ...props }, ref) => ( + <TabsPrimitive.Content + ref={ref} + className={cn( + "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", + className + )} + {...props} /> +)) +TabsContent.displayName = TabsPrimitive.Content.displayName + +export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/ventaboletos/src/components/vistas/Informacion.jsx b/ventaboletos/src/components/vistas/Informacion.jsx new file mode 100644 index 0000000..8a1ca4c --- /dev/null +++ b/ventaboletos/src/components/vistas/Informacion.jsx @@ -0,0 +1,94 @@ +import { useState, useEffect } from "react"; +import { supabaseClient } from "@/utils/supabase"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Button } from "@/components/ui/button"; + +function Informacion() { + const [open, setOpen] = useState(false); + const [conciertos, setConciertos] = useState([]); + const [selectedConcierto, setSelectedConcierto] = useState(null); + const [seatType, setSeatType] = useState(""); + + useEffect(() => { + fetchConciertos(); + }, []); + + const fetchConciertos = async () => { + let { data: conciertos, error } = await supabaseClient + .from("conciertos") + .select("*"); + if (error) { + console.error(error); + } else { + setConciertos(conciertos); + console.log(conciertos); + } + }; + + const handleSelect = (concierto) => { + setSelectedConcierto(concierto); + setOpen(true); + }; + return ( + <> + <div className="space-y-4"> + {conciertos.map((concierto) => ( + <div + key={concierto.id} + className="flex items-center gap-4 p-4 border rounded-lg" + > + <div className="w-16 h-16 bg-gray-300" /> + <div> + <p className="text-lg font-semibold">{concierto.nombre}</p> + <p className="text-sm text-gray-600">{concierto.fecha}</p> + </div> + <Button className="ml-auto" onClick={() => handleSelect(concierto)}> + Seleccionar + </Button> + </div> + ))} + </div> + <Dialog open={open} onOpenChange={setOpen}> + <DialogContent> + <DialogHeader> + <DialogTitle>{selectedConcierto?.name}</DialogTitle> + <p className="text-sm text-gray-600"> + {selectedConcierto?.location} + </p> + </DialogHeader> + <div className="space-y-4"> + <Select onValueChange={setSeatType}> + <SelectTrigger> + <SelectValue placeholder="Selecciona un tipo de asiento" /> + </SelectTrigger> + <SelectContent> + <SelectItem value="premium">Premium</SelectItem> + <SelectItem value="standard">Standard</SelectItem> + </SelectContent> + </Select> + </div> + <div className="flex justify-end gap-2 mt-4"> + <Button variant="outline" onClick={() => setOpen(false)}> + Cancelar + </Button> + <Button> Aceptar</Button> + </div> + </DialogContent> + </Dialog> + </> + ); +} + +export default Informacion; diff --git a/ventaboletos/src/components/reportes/Reporte.jsx b/ventaboletos/src/components/vistas/Reporte.jsx similarity index 100% rename from ventaboletos/src/components/reportes/Reporte.jsx rename to ventaboletos/src/components/vistas/Reporte.jsx diff --git a/ventaboletos/src/pages/index.js b/ventaboletos/src/pages/index.js index 39d7425..6af3ecf 100644 --- a/ventaboletos/src/pages/index.js +++ b/ventaboletos/src/pages/index.js @@ -1,104 +1,51 @@ -import { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; -import { supabaseClient } from "@/utils/supabase"; import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; - -/*const concerts = [ - { id: 1, name: "Concierto Fake", location: "Arena Xalapa" }, - { id: 2, name: "Concierto Fake", location: "Arena Xalapa" }, - { id: 3, name: "Concierto Fake", location: "Arena Xalapa" }, -];*/ + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import Informacion from "@/components/vistas/Informacion"; +import Reporte from "@/components/vistas/Reporte"; export default function ConcertList() { - const [open, setOpen] = useState(false); - const [conciertos, setConciertos] = useState([]); - const [selectedConcierto, setSelectedConcierto] = useState(null); - const [seatType, setSeatType] = useState(""); - - useEffect(() => { - fetchConciertos(); - }, []); - - const fetchConciertos = async () => { - let { data: conciertos, error } = await supabaseClient - .from("conciertos") - .select("*"); - if (error) { - console.error(error); - } else { - setConciertos(conciertos); - console.log(conciertos); - } - }; - - const handleSelect = (concierto) => { - setSelectedConcierto(concierto); - setOpen(true); - }; - return ( - <div className="p-6"> - <h1 className="text-2xl font-bold text-center mb-4">Boletera Bodoques</h1> - <div className="flex gap-2 justify-center mb-4"> - <Button variant="outline">Información</Button> - <Button variant="outline">Reportes</Button> + <div className="w-screen flex flex-col items-center pt-10"> + <div className="flex flex-col items-center w-[80%]"> + <Tabs defaultValue="account" className="w-full"> + <TabsList className="grid w-full grid-cols-2"> + <TabsTrigger value="info">Información</TabsTrigger> + <TabsTrigger value="reportes">Reportes</TabsTrigger> + </TabsList> + <TabsContent value="info"> + <Card> + <CardHeader> + <CardTitle></CardTitle> + <CardDescription></CardDescription> + </CardHeader> + <CardContent className="space-y-2"> + <Informacion /> + </CardContent> + <CardFooter></CardFooter> + </Card> + </TabsContent> + <TabsContent value="reportes"> + <Card> + <CardHeader> + <CardTitle></CardTitle> + <CardDescription></CardDescription> + </CardHeader> + <CardContent className="space-y-2"> + <Reporte /> + </CardContent> + <CardFooter></CardFooter> + </Card> + </TabsContent> + </Tabs> </div> - <div className="space-y-4"> - {conciertos.map((concierto) => ( - <div - key={concierto.id} - className="flex items-center gap-4 p-4 border rounded-lg" - > - <div className="w-16 h-16 bg-gray-300" /> - <div> - <p className="text-lg font-semibold">{concierto.nombre}</p> - <p className="text-sm text-gray-600">{concierto.fecha}</p> - </div> - <Button className="ml-auto" onClick={() => handleSelect(concierto)}> - Seleccionar - </Button> - </div> - ))} - </div> - <Dialog open={open} onOpenChange={setOpen}> - <DialogContent> - <DialogHeader> - <DialogTitle>{selectedConcierto?.name}</DialogTitle> - <p className="text-sm text-gray-600"> - {selectedConcierto?.location} - </p> - </DialogHeader> - <div className="space-y-4"> - <Select onValueChange={setSeatType}> - <SelectTrigger> - <SelectValue placeholder="Selecciona un tipo de asiento" /> - </SelectTrigger> - <SelectContent> - <SelectItem value="premium">Premium</SelectItem> - <SelectItem value="standard">Standard</SelectItem> - </SelectContent> - </Select> - </div> - <div className="flex justify-end gap-2 mt-4"> - <Button variant="outline" onClick={() => setOpen(false)}> - Cancelar - </Button> - <Button> Aceptar</Button> - </div> - </DialogContent> - </Dialog> </div> ); }