code:
"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { Button } from "@/app/components/ui/button";
import { Input } from "@/app/components/ui/input";
import { updatePlayerById } from "@/app/lib/actions";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
  FormDescription,
} from "@/app/components/ui/form";
import { toast } from "sonner";
import { Player } from "../lib/definitions";

const inscripcionSchema = z.object({
  fullname: z
    .string()
    .nonempty("Nombre completo es requerido")
    .min(5, { message: "El nombre debe contener al menos 5 caracteres" })
    .max(128)
    .trim(),
  city: z
    .string()
    .nonempty("Ciudad es requerido")
    .min(1, { message: "La ciudad debe contener al menos 3 caracteres" })
    .max(128)
    .trim(),
  weight: z.coerce
    .number({
      required_error: "Peso es requerido",
    })
    .positive({ message: "El peso debe ser mayor que 0" })
    .gte(20, { message: "Debe de ser a partir de 20 o más kg" }),
  height: z.coerce
    .number({
      required_error: "Altura es requerido",
    })
    .positive({ message: "La altura debe ser mayor que 0" })
    .gte(0.5, { message: "Debe de ser a partir de 0.5 mts" })
    .lte(2.5, { message: "Debe de ser menor de 2.5 mts" }),
  age: z.coerce
    .number({
      required_error: "Edad es requerido",
    })
    .int()
    .positive({ message: "La edad debe ser mayor que 0" })
    .gte(14, { message: "Debe de ser a partir de los 14 años" }),
  experience: z.coerce
    .number({
      required_error: "Experiencia es requerida",
    })
    .positive({ message: "La experiencia debe ser mayor que 0" }),
});

type InscriptionData = z.infer<typeof inscripcionSchema>;

export default function EditPlayerForm({
  player,
}: {
  player: Partial<Player>;
}) {
  const form = useForm<InscriptionData>({
    resolver: zodResolver(inscripcionSchema),
    defaultValues: {
      fullname: player.fullname || "",
      city: player.city,
      weight: player.weight,
      height: player.height,
      age: player.age,
      experience: player.experience,
    },
  });
  const playerId = player.id;

  const onSubmit = async (data: InscriptionData) => {
    try {
      if (!playerId) {
        throw new Error("ID del jugador no encontrado");
      }
      const result = inscripcionSchema.safeParse(data);
      if (!result.success) throw new Error("Data invalida");
      const { fullname, city, weight, height, age, experience } = result.data;
      toast.promise(
        updatePlayerById(playerId, {
          fullname,
          city,
          weight,
          height,
          age,
          experience,
        }),
        {
          loading: "Actualizando jugador...",
          success: () => "Jugador actualizado con éxito!",
          error: (error) => {
            if (error instanceof Error) {
              return error.message.includes("No autorizado")
                ? "Debes iniciar sesión para crear parejas"
                : error.message;
            }
            return "Error desconocido al actualizar al jugador";
          },
        }
      );
    } catch (error) {
      console.error("Unexpected error:", error);
      toast.error("Error inesperado al actualizar al jugador");
    }
  };

  return (
    <div className="px-6 py-3 sm:p-12 max-w-5xl mx-auto bg-dark/30 rounded-2xl">
      <Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
          <FormField
            control={form.control}
            name="fullname"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Nombre completo</FormLabel>
                <FormControl>
                  <Input
                    className="ring-1 ring-white/20"
                    placeholder="Rafael Nadal"
                    {...field}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="city"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Ciudad</FormLabel>
                <FormControl>
                  <Input
                    className="ring-1 ring-white/20"
                    type="text"
                    placeholder="Irapuato"
                    {...field}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="weight"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Peso</FormLabel>
                <FormControl>
                  <Input
                    className="ring-1 ring-white/20"
                    type="number"
                    placeholder="72"
                    {...field}
                  />
                </FormControl>
                <FormDescription>El peso del jugador en kg</FormDescription>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="height"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Altura</FormLabel>
                <FormControl>
                  <Input
                    className="ring-1 ring-white/20"
                    type="number"
                    placeholder="1.70"
                    {...field}
                  />
                </FormControl>
                <FormDescription>La altura del jugador en mts</FormDescription>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="age"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Edad</FormLabel>
                <FormControl>
                  <Input
                    className="ring-1 ring-white/20"
                    type="number"
                    placeholder="30"
                    {...field}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="experience"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Años de experiencia</FormLabel>
                <FormControl>
                  <Input
                    className="ring-1 ring-white/20"
                    type="number"
                    placeholder="3"
                    {...field}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <Button
            className="cursor-pointer block ml-auto text-white"
            type="submit"
            size={"lg"}
          >
            Editar jugador
          </Button>
        </form>
      </Form>
    </div>
  );
}


code:
"use client";
import ReactMarkdown from "react-markdown";

const EmotionsResults = () => {
  const test = `
   ## Análisis de sentimientos de la gran final del Torneo de las fresas

**1. Resultados del Análisis de Sentimientos:**

- **Porcentaje de Positivismo:** 20%
- **Sentimiento General:** Negativo

**2. Explicación del Sentimiento General Negativo:**

El análisis de sentimientos, utilizando dos modelos de lenguaje natural (VADER y nlptown/bert-base-multilingual-uncased-sentiment), arrojó un sentimiento general negativo, a pesar de tener un 20% de positivismo. Esto puede parecer contradictorio, pero se explica por los siguientes factores:

- **VADER:** Este modelo, al analizar el texto, detectó una alta cantidad de lenguaje neutral (98.8%) y bajos niveles de sentimiento negativo (0.5%) y positivo (0.7%). Aunque el *compound score* de VADER (0.4871) sugiere un sentimiento ligeramente positivo, este valor es susceptible a ser influenciado por la gran cantidad de texto neutral.
- **Énfasis en la Tensión y la Crítica:** El texto, aunque contiene apoyo a ciertos jugadores, también revela momentos de tensión, controversia y críticas hacia decisiones arbitrales ("robo", "mala marcación"). Estas expresiones de frustración y desacuerdo contribuyen a la percepción general de un ambiente tenso y, por lo tanto, un sentimiento general negativo.
- **Contexto del Análisis:** Es crucial entender que un análisis de sentimientos no solo detecta emociones puras, sino también la intensidad y el contexto en el que se expresan. En un evento deportivo competitivo, las emociones suelen ser intensas y fluctuantes, con momentos de alegría y decepción que se entrelazan.

**3. Análisis del Texto y su Relación con el Porcentaje de Positivismo:**

El texto analizado es una transcripción de comentarios durante el partido, lo que implica:

- **Apoyo Local:** Es evidente el apoyo a jugadores como "Macizo" (Gerardo Macizo) por parte de la afición local, generando expresiones de ánimo como "Venga macizo". Este apoyo inyecta positivismo al texto.
- **Reacciones a Jugadas Controversiales:** Las jugadas dudosas ("controversia ahí último punto") y las decisiones arbitrales cuestionables ("robo ciertamente robo mala marcación juez") provocan reacciones negativas en el público, disminuyendo el sentimiento positivo general.
- **Descripción Detallada del Juego:** Gran parte del texto se dedica a describir el desarrollo del partido, los nombres de los jugadores y los marcadores. Esta información, aunque relevante, es neutral en cuanto a sentimiento, lo que diluye el impacto de las expresiones positivas.
- **Menciones a Otros Torneos y Jugadores:** La inclusión de saludos, menciones a otros torneos y jugadores, aunque amigables, no contribuyen directamente al sentimiento positivo del partido en sí.

El "20%" de positivismo refleja el apoyo a los jugadores, los comentarios sobre buenas jugadas ("Buena bola") y el entusiasmo general por el evento. Sin embargo, este positivismo se ve opacado por la tensión del juego, las controversias y la presencia de lenguaje neutral.

**4. Conclusión sobre la Reacción del Público:**

La reacción del público durante la gran final del Torneo de las Fresas fue una mezcla de entusiasmo, apoyo y frustración. Si bien hubo un fuerte respaldo a los jugadores locales, las decisiones arbitrales polémicas y la intensidad del juego generaron momentos de tensión y críticas que influyeron en el sentimiento general. El análisis de sentimientos refleja esta dualidad, mostrando un evento deportivo apasionante donde la emoción y la controversia van de la mano.

**5. Nota Adicional:** Es importante recordar que un análisis de sentimientos es una herramienta que proporciona una visión general. Para comprender completamente la reacción del público, sería necesario complementar este análisis con otros métodos, como encuestas o entrevistas, que permitan profundizar en las emociones y percepciones de los asistentes.
`;

  return (

      {/* Rendered Markdown */}

        <ReactMarkdown>{test}</ReactMarkdown>

  );
};

export default EmotionsResults;

license: mit


code:
"use client";
import { startTransition } from "react";
import { toast } from "sonner";
import { Button } from "@/app/components/ui/button";
import { Pen } from "lucide-react";
import { createGroupsMatches } from "@/app/lib/actions";

export default function GenerateGroupsPlayers() {
  return (
    <form
      action={createGroupsMatches}
      onSubmit={(e) => {
        e.preventDefault();
        startTransition(async () => {
          try {
            await createGroupsMatches();
            toast.success("Grupos y partidos creados con exito");
          } catch (error) {
            console.log(error);
            toast.error("Error al crear grupos y partidos");
          }
        });
      }}
    >
      <Button className="cursor-pointer text-white" size={"lg"}>
        <Pen></Pen>Generar Grupos y Partidos
      </Button>
    </form>
  );
}


code:
import Link from "next/link";

const groupsColors: Record<string, string> = {
  A: "hover:from-red-900",
  B: "hover:from-yellow-900",
  C: "hover:from-emerald-900",
  D: "hover:from-cyan-900",
  E: "hover:from-rose-900",
  F: "hover:from-amber-900",
  G: "hover:from-teal-900",
  H: "hover:from-violet-900",
  I: "hover:from-teal-950",
  J: "hover:from-fuchsia-950",
  K: "hover:from-indigo-950",
  L: "hover:from-orange-950",
};

export default function Group({
  name,
  categoryId,
  groupId,
  listPairs,
}: {
  name: string;
  categoryId: string;
  groupId: string;
  listPairs: {
    pair: {
      id: string;
    };
    players: {
      id: string;
      fullname: string;
    }[];
  }[];
}) {
  return (
    <article
      className={`relative grid grid-cols-[0.8fr_1fr] border rounded-lg bg-gradient-to-b from-stone-800 to-black ${groupsColors[name]} hover:scale-105 hover:saturate-150 transition-[transform,filter]`}
    >
      <Link
        href={`/grupos/${categoryId}/${groupId}`}
        className="absolute block inset-0 z-20"
        title={`Ver enfretamientos del Grupo ${name}`}
      ></Link>

          Grupo

          {name}

          {listPairs.map((pairItem) => {
            const [player1, player2] = pairItem.players;
            return (

{player1.fullname}

{player2.fullname}

            );
          })}

  );
}


code:
export default function HeaderMap({ content }: { content: string }) {
  return <div dangerouslySetInnerHTML={{ __html: content }} />;
}


code:
"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { Button } from "@/app/components/ui/button";
import { Input } from "@/app/components/ui/input";
import { createPlayer } from "@/app/lib/actions";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
  FormDescription,
} from "@/app/components/ui/form";
import { toast } from "sonner";

const inscripcionSchema = z.object({
  fullname: z
    .string()
    .nonempty("Nombre completo es requerido")
    .min(5, { message: "El nombre debe contener al menos 5 caracteres" })
    .max(128)
    .trim(),
  city: z
    .string()
    .nonempty("Ciudad es requerido")
    .min(1, { message: "La ciudad debe contener al menos 3 caracteres" })
    .max(128)
    .trim(),
  weight: z.coerce
    .number({
      required_error: "Peso es requerido",
    })
    .positive({ message: "El peso debe ser mayor que 0" })
    .gte(20, { message: "Debe de ser a partir de 20 o más kg" }),
  height: z.coerce
    .number({
      required_error: "Altura es requerido",
    })
    .positive({ message: "La altura debe ser mayor que 0" })
    .gte(0.5, { message: "Debe de ser a partir de 0.5 mts" })
    .lte(2.5, { message: "Debe de ser menor de 2.5 mts" }),
  age: z.coerce
    .number({
      required_error: "Edad es requerido",
    })
    .int()
    .positive({ message: "La edad debe ser mayor que 0" })
    .gte(14, { message: "Debe de ser a partir de los 14 años" }),
  experience: z.coerce
    .number({
      required_error: "Experiencia es requerida",
    })
    .positive({ message: "La experiencia debe ser mayor que 0" }),
});

type InscriptionData = z.infer<typeof inscripcionSchema>;

export default function InscriptionForm() {
  const form = useForm<InscriptionData>({
    resolver: zodResolver(inscripcionSchema),
    defaultValues: {
      fullname: "",
      city: "",
    },
  });

  const onSubmit = async (data: InscriptionData) => {
    console.log(data);
    try {
      const result = inscripcionSchema.safeParse(data);
      if (!result.success) throw new Error("Data invalida");
      // fetch to craete a new group
      const { fullname, city, weight, height, age, experience } = result.data;
      toast.promise(
        createPlayer({
          fullname,
          city,
          weight,
          height,
          age,
          experience,
        }),
        {
          loading: "Inscribiendo jugador...",
          success: () => "Jugador inscrito con éxito!",
          error: (error) => {
            if (error instanceof Error) {
              return error.message.includes("No autorizado")
                ? "Debes iniciar sesión para crear parejas"
                : error.message;
            }
            return "Error desconocido al inscribir al jugador";
          },
        }
      );
    } catch (error) {
      console.error("Unexpected error:", error);
      toast.error("Error inesperado al crear la pareja");
    }
    form.reset();
  };

  return (

      <Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
          <FormField
            control={form.control}
            name="fullname"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Nombre completo</FormLabel>
                <FormControl>
                  <Input
                    className="ring-1 ring-white/20"
                    placeholder="Rafael Nadal"
                    {...field}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="city"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Ciudad</FormLabel>
                <FormControl>
                  <Input
                    className="ring-1 ring-white/20"
                    type="text"
                    placeholder="Irapuato"
                    {...field}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="weight"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Peso</FormLabel>
                <FormControl>
                  <Input
                    className="ring-1 ring-white/20"
                    type="number"
                    placeholder="72"
                    {...field}
                  />
                </FormControl>
                <FormDescription>El peso del jugador en kg</FormDescription>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="height"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Altura</FormLabel>
                <FormControl>
                  <Input
                    className="ring-1 ring-white/20"
                    type="number"
                    placeholder="1.70"
                    {...field}
                  />
                </FormControl>
                <FormDescription>La altura del jugador en mts</FormDescription>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="age"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Edad</FormLabel>
                <FormControl>
                  <Input
                    className="ring-1 ring-white/20"
                    type="number"
                    placeholder="30"
                    {...field}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="experience"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Años de experiencia</FormLabel>
                <FormControl>
                  <Input
                    className="ring-1 ring-white/20"
                    type="number"
                    placeholder="3"
                    {...field}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <Button
            className="cursor-pointer block ml-auto text-white"
            type="submit"
            size={"lg"}
            // aria-disabled={isPending}
          >
            Inscribir jugador
          </Button>
          {/*

            {errorMessage && (
              <>

{errorMessage}

              </>
            )}

 */}
        </form>
      </Form>

  );
}


code:
"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { useActionState } from "react";
import { authenticate } from "@/app/lib/actions";
import { useSearchParams } from "next/navigation";
import { startTransition } from "react";

import { Button } from "@/app/components/ui/button";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/app/components/ui/form";
import { Input } from "@/app/components/ui/input";

const formLoginSchema = z.object({
  username: z
    .string({
      required_error: "Por favor ingresa tu username",
    })
    .min(2, {
      message: "El username debe de tener por lo menos 1 caracter",
    })
    .max(128, {
      message: "El username debe de tener solo hasta 128 caracteres",
    }),
  password: z
    .string({
      required_error: "Por favor ingresa tu password",
    })
    .min(8, {
      message: "El password debe de tener por lo menos 8 caracteres",
    })
    .max(64, {
      message: "El password solo debe de tener hasta 64 caracteres",
    }),
});

export default function LoginForm() {
  const searchParams = useSearchParams();
  const callbackUrl = searchParams.get("callbackUrl") || "/dashboard";
  const [errorMessage, formAction, isPending] = useActionState(
    authenticate,
    undefined
  );

  // Define your form.
  const form = useForm<z.infer<typeof formLoginSchema>>({
    resolver: zodResolver(formLoginSchema),
    defaultValues: {
      username: "",
      password: "",
    },
  });

  async function onSubmit(values: z.infer<typeof formLoginSchema>) {
    console.log(values);
    // Use startTransition to call the server action
    startTransition(() => {
      formAction(values); // Pass validated data to the server action
    });
  }

  return (

      <Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
          <FormField
            control={form.control}
            name="username"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Username</FormLabel>
                <FormControl>
                  <Input placeholder="username" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <FormField
            control={form.control}
            name="password"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Password</FormLabel>
                <FormControl>
                  <Input type="password" placeholder="password" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <input type="hidden" name="redirectTo" value={callbackUrl} />
          <Button
            className="cursor-pointer block ml-auto text-white disabled:opacity-70"
            type="submit"
            disabled={isPending}
            aria-disabled={isPending}
          >
            Log in
          </Button>

            {errorMessage && (
              <>

{errorMessage}

              </>
            )}

        </form>
      </Form>

  );
}


code:
import Link from "next/link";

type Pair = {
  id: string;
  players: {
    id: string;
    fullname: string;
  }[];
  score: number;
};

type MatchProps = {
  pairs: Pair[];
};
export default function Match({ pairs }: MatchProps) {
  const [pair1, pair2] = pairs;
  const [player1Pair1, player2Pair1] = pair1.players;
  const pointsPair1 = pair1.score;
  const [player1Pair2, player2Pair2] = pair2.players;
  const pointsPair2 = pair2.score;

  return (

 pointsPair2 ? "bg-green-500/10" : ""
        }`}
      >

            <Link
              href={`/jugador/${player1Pair1.id}`}
              className="hover:underline transition-all"
            >
              {player1Pair1.fullname}
            </Link>

          /

            <Link
              href={`/jugador/${player2Pair1.id}`}
              className="hover:underline transition-all"
            >
              {player2Pair1.fullname}
            </Link>

          {pointsPair1}

        VS

 pointsPair1 ? "bg-green-500/10" : ""
        }`}
      >

            <Link
              href={`/jugador/${player1Pair2.id}`}
              className="hover:underline transition-all"
            >
              {player1Pair2.fullname}
            </Link>

          /

            <Link
              href={`/jugador/${player2Pair2.id}`}
              className="hover:underline transition-all"
            >
              {player2Pair2.fullname}
            </Link>

          {pointsPair2}

  );
}


code:
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { Button } from "@/app/components/ui/button";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/app/components/ui/form";
import { updateMatchScorePair } from "@/app/lib/actions";
import { toast } from "sonner";
import { Input } from "./ui/input";
import { Switch } from "./ui/switch";

const matchEditSchema = z.object({
  score: z.coerce.number().int().gte(0).lte(10),
  isWinner: z.boolean(),
});

type MatchScoreData = z.infer<typeof matchEditSchema>;

export default function MatchEditForm({
  idPair,
  idMatch,
  score,
  isWinner,
  idCategory,
}: {
  idPair: string;
  idCategory: string;
  idMatch: string;
  score: number;
  isWinner: boolean;
}) {
  const form = useForm<MatchScoreData>({
    resolver: zodResolver(matchEditSchema),
    defaultValues: {
      score: score,
      isWinner: isWinner,
    },
  });

  const onSubmit = async (pairData: MatchScoreData) => {
    try {
      const result = matchEditSchema.safeParse(pairData);
      if (!result.success) throw new Error("Invalid Data");

      const { score, isWinner } = result.data;

      toast.promise(
        updateMatchScorePair({
          idPair,
          matchId: idMatch,
          idCategory,
          updateMatchData: {
            score,
            is_winner: isWinner,
          },
        }),
        {
          loading: "Actualizando score de pareja...",
          success: () => "Score actualizado con éxito!",
          error: (error) => {
            if (error instanceof Error) {
              return error.message.includes("No autorizado")
                ? "Debes iniciar sesión para crear parejas"
                : error.message;
            }
            return "Error desconocido al actualizar el score de pareja";
          },
        }
      );
    } catch (error) {
      console.error("Unexpected error:", error);
      toast.error("Error inesperado al actualizar el score de pareja");
    }
  };

  return (
    <div className="px-6 py-3 sm:p-12 max-w-5xl mx-auto bg-dark/30 rounded-2xl">
      <Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
          {/* Campo para el score */}
          <FormField
            control={form.control}
            name="score"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Score</FormLabel>
                <FormControl>
                  <Input placeholder="Score" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />

          {/* Campo para isWinner */}
          <FormField
            control={form.control}
            name="isWinner"
            render={({ field }) => (
              <FormItem>
                <FormLabel>¿Es ganador?</FormLabel>
                <FormControl>
                  <Switch
                    checked={field.value}
                    onCheckedChange={field.onChange}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <Button
            className="cursor-pointer block ml-auto text-white mt-12"
            type="submit"
            size={"sm"}
          >
            Guardar Cambios
          </Button>
        </form>
      </Form>
    </div>
  );
}


code:
"use client";
import { ColumnDef } from "@tanstack/react-table";
import {
  DeleteMatch,
  UpdateMatch,
} from "@/app/components/dashboard/matches/buttons";

export type MatchesRow = {
  id: string;
  idCategory: string;
  group: string;
  pair1: {
    id: string;
    players: string[];
    isWinner: number;
  };
  pair2: {
    id: string;
    players: string[];
    isWinner: number;
  };
  pointsPair1: number;
  pointsPair2: number;
};

export const columns: ColumnDef<MatchesRow>[] = [
  {
    accessorKey: "group",
    header: "Grupo",
    cell: ({ row }) => {row.getValue("group")},
  },
  {
    accessorKey: "pair1",
    header: "Pareja 1",
    cell: ({ row }) => {
      const match = row.original;
      const [player1, player2] = match.pair1.players;
      return (

{player1}

          /

{player2}

      );
    },
  },
  {
    accessorKey: "pair2",
    header: "Pareja 2",
    cell: ({ row }) => {
      const match = row.original;
      const [player1, player2] = match.pair2.players;
      return (

{player1}

          /

{player2}

      );
    },
  },
  {
    accessorKey: "pointsPair1",
    header: "Puntos Pareja 1",
    cell: ({ row }) => {row.getValue("pointsPair1")},
  },
  {
    accessorKey: "pointsPair2",
    header: "Puntos Pareja 2",
    cell: ({ row }) => {row.getValue("pointsPair2")},
  },
  {
    id: "actions",
    header: "Acciones",
    cell: ({ row }) => {
      const match = row.original;
      return (

          <UpdateMatch
            id={match.id}
            idPair={match.pair1.id}
            score={match.pointsPair1}
            isWinner={Boolean(match.pair1.isWinner)}
            idCategory={match.idCategory}
          />
          <UpdateMatch
            id={match.id}
            idPair={match.pair2.id}
            score={match.pointsPair2}
            isWinner={Boolean(match.pair2.isWinner)}
            idCategory={match.idCategory}
          />
          <DeleteMatch id={match.id} idCategory={match.idCategory} />

      );
    },
  },
];


code:
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { Category } from "@/app/lib/definitions";
import { Button } from "@/app/components/ui/button";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/app/components/ui/form";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/app/components/ui/select";
import ComboBox from "@/app/components/ComboBox";
import { createMatch } from "@/app/lib/actions";
import { toast } from "sonner";

const matchesSchema = z.object({
  categoryId: z
    .string()
    .nonempty("Categoria requerida")
    .length(36, { message: "Categoria no valida" }),
  matchStatus: z
    .string()
    .nonempty("Match Status requerido")
    .length(36, { message: "Match Status no valido" }),
  matchCategory: z
    .string()
    .nonempty("Match Category requerido")
    .length(36, { message: "Match Category no valido" }),
  pair1Id: z.string().nonempty("Pareja 1 requerido"),
  pair2Id: z.string().nonempty("Pareja 2 requerido"),
});
type PairsData = z.infer<typeof matchesSchema>;

export default function MatchesForm({
  pairsList,
  categoriesList,
  matchCategoriesList,
  mastStatusList,
}: {
  pairsList: [];
  categoriesList: Category[];
  matchCategoriesList: Category[];
  mastStatusList: Category[];
}) {
  // fetch the categories and the players
  const form = useForm<PairsData>({
    resolver: zodResolver(matchesSchema),
    defaultValues: {},
  });

  const onSubmit = async (pairData: PairsData) => {
    console.log({ pairData });
    try {
      const result = matchesSchema.safeParse(pairData);
      if (!result.success) throw new Error("Invalid Data");
      // fetch to craete a new group
      const { matchCategory, matchStatus, categoryId, pair1Id, pair2Id } =
        result.data;
      console.log({ pair1Id, pair2Id, categoryId });
      toast.promise(
        createMatch({
          registration_category_id: categoryId,
          match_category_id: matchCategory,
          match_status_id: matchStatus,
          pairs: [pair1Id, pair2Id],
        }),
        {
          loading: "Creando partido...",
          success: () => "Partido creado con éxito!",
          error: (error) => {
            if (error instanceof Error) {
              return error.message.includes("No autorizado")
                ? "Debes iniciar sesión para crear partidos"
                : error.message;
            }
            return "Error desconocido al crear el partido";
          },
        }
      );
    } catch (error) {
      console.error("Unexpected error:", error);
      toast.error("Error inesperado al crear el partido");
    }
    form.reset();
  };

  return (
    <div className="px-6 py-3 sm:p-12 max-w-5xl mx-auto bg-dark/30 rounded-2xl">
      <Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
          {/* Pair 1 */}
          <ComboBox
            labelField="Pareja 1"
            name="pair1Id"
            control={form.control}
            suggestions={pairsList}
          />
          {/* Pair 2 */}
          <ComboBox
            labelField="Pareja 2"
            name="pair2Id"
            control={form.control}
            suggestions={pairsList}
          />
          {/* Categories */}
          <FormField
            control={form.control}
            name="categoryId"
            render={({ field }) => (
              <Select onValueChange={field.onChange} value={field.value}>
                <FormItem>
                  <FormLabel>Categoria</FormLabel>
                  <FormControl>
                    <SelectTrigger className="w-full">
                      <SelectValue placeholder="Selecciona la categoria" />
                    </SelectTrigger>
                  </FormControl>
                  <SelectContent>
                    {categoriesList.map((category) => {
                      return (
                        <SelectItem
                          key={`category-${category.id}`}
                          value={category.id}
                        >
                          {category.description}
                        </SelectItem>
                      );
                    })}
                  </SelectContent>
                  <FormMessage />
                </FormItem>
              </Select>
            )}
          />
          {/* Match status */}
          <FormField
            control={form.control}
            name="matchStatus"
            render={({ field }) => (
              <Select onValueChange={field.onChange} value={field.value}>
                <FormItem>
                  <FormLabel>Match Status</FormLabel>
                  <FormControl>
                    <SelectTrigger className="w-full">
                      <SelectValue placeholder="Selecciona el match status" />
                    </SelectTrigger>
                  </FormControl>
                  <SelectContent>
                    {mastStatusList.map((matchStatus) => {
                      return (
                        <SelectItem
                          key={`matchStatus-${matchStatus.id}`}
                          value={matchStatus.id}
                        >
                          {matchStatus.description}
                        </SelectItem>
                      );
                    })}
                  </SelectContent>
                  <FormMessage />
                </FormItem>
              </Select>
            )}
          />
          {/* Match category */}
          <FormField
            control={form.control}
            name="matchCategory"
            render={({ field }) => (
              <Select onValueChange={field.onChange} value={field.value}>
                <FormItem>
                  <FormLabel>Match Category</FormLabel>
                  <FormControl>
                    <SelectTrigger className="w-full">
                      <SelectValue placeholder="Selecciona el match status" />
                    </SelectTrigger>
                  </FormControl>
                  <SelectContent>
                    {matchCategoriesList.map((matchCategory) => {
                      return (
                        <SelectItem
                          key={`matchCategory-${matchCategory?.id}`}
                          value={matchCategory?.id}
                        >
                          {matchCategory?.description}
                        </SelectItem>
                      );
                    })}
                  </SelectContent>
                  <FormMessage />
                </FormItem>
              </Select>
            )}
          />
          <Button
            className="cursor-pointer block ml-auto text-white mt-12"
            type="submit"
            size={"lg"}
          >
            Agregar Partido
          </Button>
        </form>
      </Form>
    </div>
  );
}


code:
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { Player, Category } from "@/app/lib/definitions";
import { Button } from "@/app/components/ui/button";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/app/components/ui/form";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/app/components/ui/select";
import ComboBox from "@/app/components/ComboBox";
import { updatePairById } from "@/app/lib/actions";
import { toast } from "sonner";

const pairsSchema = z
  .object({
    player1Id: z.string().nonempty("Jugador 1 requerido"),
    player2Id: z.string().nonempty("Jugador 2 requerido"),
    categoryId: z
      .string()
      .nonempty("Categoria requerida")
      .length(36, { message: "Categoria no valida" }),
  })
  .refine((data) => data.player1Id !== data.player2Id, {
    message: "Error, selecciona diferentes jugadores para crear una pareja",
    path: ["confirm"], // path of error
  });

type PairsData = z.infer<typeof pairsSchema>;

export default function PairsEditForm({
  pair,
  playersList,
  categoriesList,
}: {
  pair: {
    id: string;
    categoryId: string;
    playersIds: {
      idPlayer: string;
    }[];
  };
  playersList: Player[];
  categoriesList: Category[];
}) {
  const [player1, player2] = pair.playersIds;
  const form = useForm<PairsData>({
    resolver: zodResolver(pairsSchema),
    defaultValues: {
      player1Id: player1.idPlayer,
      player2Id: player2.idPlayer,
      categoryId: pair.categoryId,
    },
  });

  const updatePairByIdWithId = updatePairById.bind(null, pair.id);

  const onSubmit = async (pairData: PairsData) => {
    try {
      const result = pairsSchema.safeParse(pairData);
      if (!result.success) throw new Error("Invalid Data");
      // fetch to craete a new group
      const { player1Id, player2Id, categoryId } = result.data;
      console.log(result.data);
      updatePairByIdWithId({
        players: [player1Id, player2Id],
        registration_category_id: categoryId,
      });
    } catch (error) {
      console.error("Unexpected error:", error);
      toast.error("Error inesperado al crear la pareja");
    }
  };

  return (
    <div className="px-6 py-3 sm:p-12 max-w-5xl mx-auto bg-dark/30 rounded-2xl">
      <Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
          <ComboBox
            labelField="Jugador 1"
            name="player1Id"
            control={form.control}
            suggestions={playersList}
          />
          <ComboBox
            labelField="Jugador 2"
            name="player2Id"
            control={form.control}
            suggestions={playersList}
          />
          <FormField
            control={form.control}
            name="categoryId"
            render={({ field }) => (
              <Select onValueChange={field.onChange} value={field.value}>
                <FormItem>
                  <FormLabel>Categoria</FormLabel>
                  <FormControl>
                    <SelectTrigger className="w-full">
                      <SelectValue placeholder="Selecciona la categoria" />
                    </SelectTrigger>
                  </FormControl>
                  <SelectContent>
                    {categoriesList.map((category) => {
                      return (
                        <SelectItem
                          key={`category-${category.id}`}
                          value={category.id}
                        >
                          {category.description}
                        </SelectItem>
                      );
                    })}
                  </SelectContent>
                  <FormMessage />
                </FormItem>
              </Select>
            )}
          />
          <Button
            className="cursor-pointer block ml-auto text-white mt-12"
            type="submit"
            size={"lg"}
            // aria-disabled={isPending}
          >
            Guardar Cambios
          </Button>
        </form>
      </Form>
    </div>
  );
}


code:
"use client";
import { ColumnDef } from "@tanstack/react-table";
import Link from "next/link";
import { DeletePair } from "@/app/components/dashboard/pairs/buttons";

export type PairRow = {
  id: string;
  player1: {
    id: string;
    name: string;
  };
  player2: {
    id: string;
    name: string;
  };
  category: "Libre" | "Seniors";
};

export const columnsPublic: ColumnDef<PairRow>[] = [
  {
    accessorKey: "player1",
    header: "Jugador 1",
    cell: ({ row }) => (
      <Link
        href={`/jugador/${row.original.player1.id}`}
        className="hover:underline transition-all"
      >
        {row.original.player1.name}
      </Link>
    ),
  },
  {
    accessorKey: "player2",
    header: "Jugador 2",
    cell: ({ row }) => (
      <Link
        href={`/jugador/${row.original.player2.id}`}
        className="hover:underline transition-all"
      >
        {row.original.player2.name}
      </Link>
    ),
  },
  {
    accessorKey: "category",
    header: "Categoria",
    cell: ({ row }) => {row.getValue("category")},
  },
];

export const columns: ColumnDef<PairRow>[] = [
  {
    accessorKey: "player1",
    header: "Jugador 1",
    cell: ({ row }) => (
      <Link
        href={`/jugador/${row.original.player1.id}`}
        className="hover:underline transition-all"
      >
        {row.original.player1.name}
      </Link>
    ),
  },
  {
    accessorKey: "player2",
    header: "Jugador 2",
    cell: ({ row }) => (
      <Link
        href={`/jugador/${row.original.player2.id}`}
        className="hover:underline transition-all"
      >
        {row.original.player2.name}
      </Link>
    ),
  },
  {
    accessorKey: "category",
    header: "Categoria",
    cell: ({ row }) => {row.getValue("category")},
  },
  {
    id: "actions",
    header: "Acciones",
    cell: ({ row }) => {
      const pair = row.original;
      return (

          <DeletePair id={pair.id} />

      );
    },
  },
];


code:
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { Player, Category } from "@/app/lib/definitions";
import { Button } from "@/app/components/ui/button";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/app/components/ui/form";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/app/components/ui/select";
import ComboBox from "@/app/components/ComboBox";
import { createPair } from "@/app/lib/actions";
import { toast } from "sonner";

const pairsSchema = z
  .object({
    player1Id: z.string().nonempty("Jugador 1 requerido"),
    player2Id: z.string().nonempty("Jugador 2 requerido"),
    categoryId: z
      .string()
      .nonempty("Categoria requerida")
      .length(36, { message: "Categoria no valida" }),
  })
  .refine((data) => data.player1Id !== data.player2Id, {
    message: "Error, selecciona diferentes jugadores para crear una pareja",
    path: ["confirm"], // path of error
  });

type PairsData = z.infer<typeof pairsSchema>;

export default function PairsForm({
  playersList,
  categoriesList,
}: {
  playersList: Player[];
  categoriesList: Category[];
}) {
  // fetch the categories and the players
  const form = useForm<PairsData>({
    resolver: zodResolver(pairsSchema),
    defaultValues: {
      player1Id: "",
      player2Id: "",
      categoryId: "",
    },
  });

  const onSubmit = async (pairData: PairsData) => {
    console.log({ pairData });
    try {
      const result = pairsSchema.safeParse(pairData);
      if (!result.success) throw new Error("Invalid Data");
      // fetch to craete a new group
      const { player1Id, player2Id, categoryId } = result.data;
      console.log({ player1Id, player2Id, categoryId });
      toast.promise(
        createPair({
          players: [player1Id, player2Id],
          registration_category_id: categoryId,
        }),
        {
          loading: "Creando pareja...",
          success: () => "Pareja creada con éxito!",
          error: (error) => {
            if (error instanceof Error) {
              return error.message.includes("No autorizado")
                ? "Debes iniciar sesión para crear parejas"
                : error.message;
            }
            return "Error desconocido al crear la pareja";
          },
        }
      );
    } catch (error) {
      console.error("Unexpected error:", error);
      toast.error("Error inesperado al crear la pareja");
    }
    form.reset();
  };

  return (

      <Form {...form}>
        <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
          <ComboBox
            labelField="Jugador 1"
            name="player1Id"
            control={form.control}
            suggestions={playersList}
          />
          <ComboBox
            labelField="Jugador 2"
            name="player2Id"
            control={form.control}
            suggestions={playersList}
          />
          <FormField
            control={form.control}
            name="categoryId"
            render={({ field }) => (
              <Select onValueChange={field.onChange} value={field.value}>
                <FormItem>
                  <FormLabel>Categoria</FormLabel>
                  <FormControl>
                    <SelectTrigger className="w-full">
                      <SelectValue placeholder="Selecciona la categoria" />
                    </SelectTrigger>
                  </FormControl>
                  <SelectContent>
                    {categoriesList.map((category) => {
                      return (
                        <SelectItem
                          key={`category-${category.id}`}
                          value={category.id}
                        >
                          {category.description}
                        </SelectItem>
                      );
                    })}
                  </SelectContent>
                  <FormMessage />
                </FormItem>
              </Select>
            )}
          />
          <Button
            className="cursor-pointer block ml-auto text-white mt-12"
            type="submit"
            size={"lg"}
            // aria-disabled={isPending}
          >
            Agregar Pareja
          </Button>
          {/*

        {errorMessage && (
          <>

{errorMessage}

          </>
        )}

 */}
        </form>
      </Form>

  );
}


code:
"use client";
import { ColumnDef } from "@tanstack/react-table";
import Link from "next/link";
import {
  DeletePlayer,
  UpdatePlayer,
} from "@/app/components/dashboard/players/buttons";

export type PlayerRow = {
  id: string;
  fullname: string;
  city: string;
  weight: string;
  height: string;
};

export const columns: ColumnDef<PlayerRow>[] = [
  {
    accessorKey: "fullname",
    header: "Nombre",
    cell: ({ row }) => (
      <Link
        href={`/jugador/${row.original.id}`}
        className="hover:underline transition-all"
      >
        {row.original.fullname}
      </Link>
    ),
  },
  {
    accessorKey: "city",
    header: "Ciudad",
    cell: ({ row }) => {row.getValue("city")},
  },
  {
    accessorKey: "weight",
    header: "Peso",
    cell: ({ row }) => {row.getValue("weight")},
  },
  {
    accessorKey: "height",
    header: "Altura",
    cell: ({ row }) => {row.getValue("height")},
  },
  {
    id: "actions",
    header: "Acciones",
    cell: ({ row }) => {
      const player = row.original;
      return (

          <UpdatePlayer id={player.id} />
          <DeletePlayer id={player.id} />

      );
    },
  },
];


code:
export default function SquareBackground() {
  return (

div]:w-full [&>div]:aspect-square [&>div]:rounded-md [&>div]:bg-primary/10">

  );
}


code:
"use client";
import { useState } from "react";
import {
  ColumnDef,
  ColumnFiltersState,
  flexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  useReactTable,
} from "@tanstack/react-table";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/app/components/ui/table";
import { Input } from "@/app/components/ui/input";
import { Button } from "./ui/button";

interface DataTableProps<TData, TValue> {
  columns: ColumnDef<TData, TValue>[];
  data: TData[];
}

export default function DataTable<TData, TValue>({
  columns,
  data,
}: DataTableProps<TData, TValue>) {
  const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
  // console.log({ dataTable: data });

  const table = useReactTable({
    data,
    columns,
    onColumnFiltersChange: setColumnFilters,
    getFilteredRowModel: getFilteredRowModel(),
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    state: {
      columnFilters,
    },
    globalFilterFn: (row, columnId, filterValue) => {
      // Custom global filter logic for player1 and player2
      const player1Name =
        (
          row.original as { player1: { name: string } }
        ).player1?.name?.toLowerCase() ?? "";
      const player2Name =
        (
          row.original as { player2: { name: string } }
        ).player2?.name?.toLowerCase() ?? "";
      const filterTerm = String(filterValue).toLowerCase();

      return (
        player1Name.includes(filterTerm) || player2Name.includes(filterTerm)
        // || String(row.getValue(columnId)).toLowerCase().includes(filterTerm)
      );
    },
  });

  return (

        <Input
          placeholder="Filtrar  nombres..."
          value={(table.getState().globalFilter as string) ?? ""}
          onChange={(event) => table.setGlobalFilter(event.target.value)}
          className="max-w-sm"
        />

          {/* Headers */}
          <TableHeader>
            {table.getHeaderGroups().map((headerGroup) => (
              <TableRow key={headerGroup.id}>
                {headerGroup.headers.map((header) => (
                  <TableHead key={header.id}>
                    {flexRender(
                      header.column.columnDef.header,
                      header.getContext()
                    )}
                  </TableHead>
                ))}
              </TableRow>
            ))}
          </TableHeader>
          {/* Body Table */}
          <TableBody>
            {/* Render the rows */}
            {table.getRowModel().rows?.length ? (
              table.getRowModel().rows.map((row) => (
                <TableRow key={row.id}>
                  {row.getVisibleCells().map((cell) => (
                    <TableCell key={cell.id}>
                      {flexRender(
                        cell.column.columnDef.cell,
                        cell.getContext()
                      )}
                    </TableCell>
                  ))}
                </TableRow>
              ))
            ) : (
              <TableRow>
                <TableCell
                  colSpan={columns.length}
                  className="h-24 text-center"
                >
                  No results.
                </TableCell>
              </TableRow>
            )}
          </TableBody>

        <Button
          variant="outline"
          size="sm"
          onClick={() => table.previousPage()}
          disabled={!table.getCanPreviousPage()}
          className="cursor-pointer"
        >
          Anterior
        </Button>
        <Button
          variant="outline"
          size="sm"
          onClick={() => table.nextPage()}
          disabled={!table.getCanNextPage()}
          className="cursor-pointer"
        >
          Siguiente
        </Button>

  );
}


code:
"use client";
import { useState } from "react";
import {
  ColumnDef,
  ColumnFiltersState,
  flexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  useReactTable,
} from "@tanstack/react-table";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/app/components/ui/table";
import { Input } from "@/app/components/ui/input";
import { Button } from "./ui/button";

interface DataTableProps<TData, TValue> {
  columns: ColumnDef<TData, TValue>[];
  data: TData[];
}

export default function DataTablePlayers<TData, TValue>({
  columns,
  data,
}: DataTableProps<TData, TValue>) {
  const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
  // console.log({ dataTable: data });

  const table = useReactTable({
    data,
    columns,
    onColumnFiltersChange: setColumnFilters,
    getFilteredRowModel: getFilteredRowModel(),
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    state: {
      columnFilters,
    },
    globalFilterFn: (row, columnId, filterValue) => {
      // Custom global filter logic for player1 and player2
      const playerName =
        (row.original as { fullname: string }).fullname.toLowerCase() ?? "";
      const filterTerm = String(filterValue).toLowerCase();

      return playerName.includes(filterTerm);
      // || String(row.getValue(columnId)).toLowerCase().includes(filterTerm)
    },
  });

  return (

        <Input
          placeholder="Filtrar  nombres..."
          value={(table.getState().globalFilter as string) ?? ""}
          onChange={(event) => table.setGlobalFilter(event.target.value)}
          className="max-w-sm"
        />

          {/* Headers */}
          <TableHeader>
            {table.getHeaderGroups().map((headerGroup) => (
              <TableRow key={headerGroup.id}>
                {headerGroup.headers.map((header) => (
                  <TableHead key={header.id}>
                    {flexRender(
                      header.column.columnDef.header,
                      header.getContext()
                    )}
                  </TableHead>
                ))}
              </TableRow>
            ))}
          </TableHeader>
          {/* Body Table */}
          <TableBody>
            {/* Render the rows */}
            {table.getRowModel().rows?.length ? (
              table.getRowModel().rows.map((row) => (
                <TableRow key={row.id}>
                  {row.getVisibleCells().map((cell) => (
                    <TableCell key={cell.id}>
                      {flexRender(
                        cell.column.columnDef.cell,
                        cell.getContext()
                      )}
                    </TableCell>
                  ))}
                </TableRow>
              ))
            ) : (
              <TableRow>
                <TableCell
                  colSpan={columns.length}
                  className="h-24 text-center"
                >
                  No results.
                </TableCell>
              </TableRow>
            )}
          </TableBody>

        <Button
          variant="outline"
          size="sm"
          onClick={() => table.previousPage()}
          disabled={!table.getCanPreviousPage()}
          className="cursor-pointer"
        >
          Anterior
        </Button>
        <Button
          variant="outline"
          size="sm"
          onClick={() => table.nextPage()}
          disabled={!table.getCanNextPage()}
          className="cursor-pointer"
        >
          Siguiente
        </Button>

  );
}


code:
import { Edit, Trash } from "lucide-react";
import { Button } from "@/app/components/ui/button";
import { deleteMatchById } from "@/app/lib/actions";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/app/components/ui/alert-dialog";
import { startTransition } from "react";
import { toast } from "sonner";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "../../ui/dialog";
import MatchEditForm from "../../MatchEditForm";

export function UpdateMatch({
  id,
  idPair,
  score,
  isWinner,
  idCategory,
}: {
  id: string;
  idPair: string;
  score: number;
  isWinner: boolean;
  idCategory: string;
}) {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="outline">
          <Edit />
        </Button>
      </DialogTrigger>
      <DialogContent className="sm:max-w-[425px]">
        <DialogHeader>
          <DialogTitle>Editar Score Pareja 1</DialogTitle>
          {/* <DialogDescription>
            Make changes to your profile here. Click save when you're done.
          </DialogDescription> */}
        </DialogHeader>
        <div className="mt-6">
          <MatchEditForm
            idMatch={id}
            idPair={idPair}
            idCategory={idCategory}
            score={score}
            isWinner={isWinner}
          />
        </div>
      </DialogContent>
    </Dialog>
  );
}

export function DeleteMatch({
  id,
  idCategory,
}: {
  id: string;
  idCategory: string;
}) {
  const deleteMatchWithId = deleteMatchById.bind(null, { id, idCategory });

  return (
    <AlertDialog>
      <AlertDialogTrigger asChild>
        <Button
          type="submit"
          variant="outline"
          size="sm"
          className="cursor-pointer"
        >
          <Trash className="w-4 h-4 " />
        </Button>
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>¿Estas seguro?</AlertDialogTitle>
          <AlertDialogDescription>
            Esta acción no se puede deshacer. Eliminará el partido y sus datos
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancelar</AlertDialogCancel>
          <form
            action={deleteMatchWithId}
            onSubmit={(e) => {
              e.preventDefault();
              startTransition(async () => {
                try {
                  await deleteMatchWithId();
                  toast.success("Eliminado con éxito");
                } catch (error) {
                  console.log(error);
                  toast.error("Error al eliminar");
                }
              });
            }}
          >
            <AlertDialogAction type="submit">Eliminar</AlertDialogAction>
          </form>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  );
}


code:
import Link from "next/link";
import { Edit, Trash } from "lucide-react";
import { Button } from "@/app/components/ui/button";
import { deletePairById } from "@/app/lib/actions";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/app/components/ui/alert-dialog";
import { startTransition } from "react";
import { toast } from "sonner";

export function UpdatePair({ id }: { id: string }) {
  return (
    <Link
      href={`/dashboard/parejas/${id}/editar`}
      className="rounded-md border p-2 hover:bg-dark/50"
    >
      <Edit className="w-4 h-4" />
    </Link>
  );
}

export function DeletePair({ id }: { id: string }) {
  const deletePairWithId = deletePairById.bind(null, id);

  return (
    <AlertDialog>
      <AlertDialogTrigger asChild>
        <Button
          type="submit"
          variant="outline"
          size="sm"
          className="cursor-pointer"
        >
          <Trash className="w-4 h-4 " />
        </Button>
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>¿Estas seguro?</AlertDialogTitle>
          <AlertDialogDescription>
            Esta acción no se puede deshacer. Eliminará a la pareja y sus datos
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancelar</AlertDialogCancel>
          <form
            action={deletePairWithId}
            onSubmit={(e) => {
              e.preventDefault();
              startTransition(async () => {
                try {
                  await deletePairWithId();
                  toast.success("Eliminado con éxito");
                } catch (error) {
                  console.log(error);
                  toast.error("Error al eliminar");
                }
              });
            }}
          >
            <AlertDialogAction type="submit">Eliminar</AlertDialogAction>
          </form>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  );
}


code:
import Link from "next/link";
import { Edit, Trash } from "lucide-react";
import { Button } from "@/app/components/ui/button";
import { deletePlayerById } from "@/app/lib/actions";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/app/components/ui/alert-dialog";
import { startTransition } from "react";
import { toast } from "sonner";

export function UpdatePlayer({ id }: { id: string }) {
  return (
    <Link
      href={`/dashboard/jugadores/${id}/editar`}
      className="rounded-md border p-2 hover:bg-dark/50"
    >
      <Edit className="w-4 h-4" />
    </Link>
  );
}

export function DeletePlayer({ id }: { id: string }) {
  const deletePlayerWithId = deletePlayerById.bind(null, id);

  return (
    <AlertDialog>
      <AlertDialogTrigger asChild>
        <Button
          type="submit"
          variant="outline"
          size="sm"
          className="cursor-pointer"
        >
          <Trash className="w-4 h-4 " />
        </Button>
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>¿Estas seguro?</AlertDialogTitle>
          <AlertDialogDescription>
            Esta acción no se puede deshacer. Eliminará al jugador y sus datos
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancelar</AlertDialogCancel>
          <form
            action={deletePlayerWithId}
            onSubmit={(e) => {
              e.preventDefault();
              startTransition(async () => {
                try {
                  await deletePlayerWithId();
                  toast.success("Eliminado con éxito");
                } catch (error) {
                  console.log(error);
                  toast.error("Error al eliminar");
                }
              });
            }}
          >
            <AlertDialogAction type="submit">Eliminar</AlertDialogAction>
          </form>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  );
}


code:
export default function BentoCard({
  children,
  className,
}: {
  children: React.ReactNode;
  className?: string;
}) {
  return (
    <article
      className={`p-10 bg-white text-black rounded-lg overflow-hidden  before:absolute before:content-[''] before:block before:w-full before:h-full before:inset-0 before:-z-10 ${className}`}
      style={{
        background: `linear-gradient(90deg, hsl(210 11% 25% / 0.4) 1px, transparent 1px 10vmin) 50% -5vmin / 5vmin 5vmin, linear-gradient(hsl(210 11% 25% / 0.4) 1px, transparent 1px 10vmin) 50% -5vmin / 5vmin 5vmin, white`,
      }}
    >
      {children}
    </article>
  );
}


code:
export default function CardTime({
  title,
  copy,
  time,
}: {
  title: string;
  copy: string;
  time: string;
}) {
  return (

        {time}

          {title}

{copy}

  );
}


code:
import React from "react";

export default function Container({
  children,
  className = "",
}: {
  children: React.ReactNode;
  className?: string;
}) {
  return <div className={`w-[80%] mx-auto ${className}`}>{children}
;
}


code:
"use client";
import { useEffect, useState } from "react";
import Image from "next/image";
import merchData from "@/app/data/merch.json";

export default function Merch() {
  const [indexMerchItem, setIndexMerchItem] = useState(0);
  const [principalImg, setPrincipalImg] = useState("");

  useEffect(() => {
    setPrincipalImg(merchData[indexMerchItem].images[0]);
  }, [indexMerchItem]);

  const handleChangeShirtMerch = () => {
    setIndexMerchItem(0);
  };

  const handleChangeCapMerch = () => {
    setIndexMerchItem(1);
  };

  const handleChangeImg = (imgUrl: string) => {
    setPrincipalImg(imgUrl);
  };

  const merchItem = merchData[indexMerchItem];

  return (

        <button
          className={`px-4 xs:px-6 py-3 border cursor-pointer xs:min-w-[150px] hover:bg-primary-darker hover:text-white transition-colors ${
            indexMerchItem === 0 && "bg-primary-darker text-white"
          }`}
          onClick={handleChangeShirtMerch}
        >
          Ver Playera
        </button>
        <button
          className={`px-6 py-3 border cursor-pointer xs:min-w-[150px] hover:bg-primary-darker hover:text-white transition-colors ${
            indexMerchItem === 1 && "bg-primary-darker text-white"
          }`}
          onClick={handleChangeCapMerch}
        >
          Ver Gorra
        </button>

          {/* Options */}

            {merchItem.images.map((imageUrl) => {
              return (
                <button
                  key={`merch-${imageUrl}`}
                  className="cursor-pointer"
                  onClick={() => handleChangeImg(imageUrl)}
                >
                  <picture className="inline-block p-3 border border-dotted border-gray-400 bg-gray-200">
                    <Image
                      src={imageUrl}
                      alt="Imagen"
                      width={340}
                      height={340}
                      className="max-w-[70px]"
                    />
                  </picture>
                </button>
              );
            })}

          {/* Principal Img */}
          {principalImg && (
            <picture className="lg:w-[340px] inline-block p-8 bg-gray-300">
              <Image
                src={principalImg}
                alt="Merch TDLF-2025"
                width={340}
                height={340}
                className="sm:max-w-[300px] w-full h-full aspect-square object-cover"
              />
            </picture>
          )}

        {/* Merch Info */}

{merchItem.title}

{merchItem.description}

            Ver todo el catalogo

  );
}


code:
"use client";

import React, { useRef } from "react";

export function MouseFollowWrapper({
  children,
}: {
  children: React.ReactNode;
}) {
  const cardsContainerRef = useRef<HTMLDivElement | null>(null);

  const handleMouseMove = (event: React.MouseEvent<HTMLElement>) => {
    const cards = cardsContainerRef.current?.children;
    if (cards) {
      for (const card of Array.from(cards)) {
        if (card instanceof HTMLElement) {
          const rect = card.getBoundingClientRect();
          const x = event.clientX - rect.left;
          const y = event.clientY - rect.top;
          card.style.setProperty("--mouse-x", `${x}px`);
          card.style.setProperty("--mouse-y", `${y}px`);
        }
      }
    }
  };

  return (

      {children}

  );
}

export function MouseFollowCard({ children }: { children: React.ReactNode }) {
  return (

      <div
        className="h-full w-full absolute top-0 left-0 transition-opacity z-20 opacity-0 group-hover/card:opacity-100"
        style={{
          background: `radial-gradient(800px circle at var(--mouse-x) var(--mouse-y),#e6135733,transparent 40%)`,
        }}
      >

      <div
        className="h-full w-full absolute top-0 left-0 transition-opacity z-10"
        style={{
          background: `radial-gradient(600px circle at var(--mouse-x) var(--mouse-y),#e6135733,transparent 40%)`,
        }}
      >

      {children}

  );
}


code:
"use client";

import React, { useRef } from "react";

export default function PlayCards() {
  const cardsContainerRef = useRef<HTMLDivElement | null>(null);

  const handleMouseMove = (event: React.MouseEvent<HTMLElement>) => {
    const cards = cardsContainerRef.current?.children;
    if (cards) {
      for (const card of Array.from(cards)) {
        if (card instanceof HTMLElement) {
          const rect = card.getBoundingClientRect();
          const x = event.clientX - rect.left;
          const y = event.clientY - rect.top;
          card.style.setProperty("--mouse-x", `${x}px`);
          card.style.setProperty("--mouse-y", `${y}px`);
        }
      }
    }
  };

  return (

        <div
          className="h-full w-full absolute top-0 left-0 transition-opacity z-20 opacity-0 group-hover/card:opacity-100"
          style={{
            background: `radial-gradient(800px circle at var(--mouse-x) var(--mouse-y),#e6135733,transparent 40%)`,
          }}
        >

        <div
          className="h-full w-full absolute top-0 left-0 transition-opacity z-10"
          style={{
            background: `radial-gradient(600px circle at var(--mouse-x) var(--mouse-y),#e6135733,transparent 40%)`,
          }}
        >

            Reglas claras, competencia intensa{" "}

              ¡Así se juega en nuestro torneo!

              Partidos a 10 puntos o 20 minutos. Gana quien llegue a 10 o tenga
              la ventaja al finalizar el tiempo.

Se juega un punto para determinar quién saca.

              Si no se presenta una pareja en 5 minutos, se considera pérdida
              por default, y se asignan solo 5 puntos a la pareja ganadora.

              La pareja ganadora actúa como juez de línea y juez central en el
              siguiente partido.

        <div
          className="h-full w-full absolute top-0 left-0 transition-opacity z-20 opacity-0 group-hover/card:opacity-100"
          style={{
            background: `radial-gradient(800px circle at var(--mouse-x) var(--mouse-y),#e6135733,transparent 40%)`,
          }}
        >

        <div
          className="h-full w-full absolute top-0 left-0 transition-opacity z-10"
          style={{
            background: `radial-gradient(600px circle at var(--mouse-x) var(--mouse-y),#e6135733,transparent 40%)`,
          }}
        >

            ¡Solo los mejores avanzan!{" "}

              ¿Podras avanzar a la próxima fase?

Detalles para avanzar:

Se juega por sistema de doble eliminación.

              Una pareja queda eliminada del torneo tras perder dos partidos.{" "}

              Avanzan a la siguiente fase las dos primeras parejas de cada
              grupo.

              Las parejas se clasifican en función de los partidos ganados, y en
              caso de empate, se desempatará por los puntos obtenidos.

        <div
          className="h-full w-full absolute top-0 left-0 transition-opacity z-20 opacity-0 group-hover/card:opacity-100"
          style={{
            background: `radial-gradient(800px circle at var(--mouse-x) var(--mouse-y),#e6135733,transparent 40%)`,
          }}
        >

        <div
          className="h-full w-full absolute top-0 left-0 transition-opacity z-10"
          style={{
            background: `radial-gradient(600px circle at var(--mouse-x) var(--mouse-y),#e6135733,transparent 40%)`,
          }}
        >

            ¡Todo bajo control!{" "}
            Consejos clave para competir

Prepara tu juego:

              Las parejas deberán ir uniformados, playera del mismo color o
              similar.

              Los lentes de protección no son obligatorios, más si
              recomendables.

Recomendable el uso de gorra y bloqueador.

Lleva toalla para el sudor y mantente hidratado.

Ve el status de tu posición en la página de tu grupo.

  );
}


code:
// Sections components
export { default as Header } from "./sections/Header";
export { default as Hero } from "./sections/Hero";
export { default as Info } from "./Info";
export { default as NeedToKnow } from "./sections/NeedToKnow";
export { default as Agenda } from "./sections/Agenda";
export { default as HowToPlay } from "./sections/HowToPlay";
export { default as Sponsors } from "./sections/Sponsors";
export { default as Awards } from "./sections/Awards";
export { default as PreFooter } from "./sections/PreFooter";
export { default as Footer } from "./sections/Footer";
// Components
export { default as Container } from "./Container";
export { default as BentoCard } from "./BentoCard";
export { default as PlayCards } from "./PlayCards";
export { default as CardTime } from "./CardTime";
export { default as Merch } from "./Merch";


code:
"use client";
import { Container, CardTime } from "@/app/components/landing";
import agendaData from "@/app/data/agenda.json";
import { useEffect, useRef } from "react";
import styles from "@/app/styles/landing.module.css";

export default function Agenda() {
  const agendaListRef = useRef<HTMLUListElement | null>(null);

  useEffect(() => {
    const listItems = agendaListRef.current?.children;
    if (listItems) {
      Array.from(listItems).forEach((itemAgenda, index) => {
        if (itemAgenda instanceof HTMLElement) {
          itemAgenda.style?.setProperty("--index-agenda", `${index + 1}`);
        }
      });
    }
  }, []);

  return (

      <Container>

Agenda

            23 de Marzo de 2025
            {/* <button className="cursor-pointer">Agenda tu Calendario</button> */}

        <ul
          className={`${styles.animation__scrollin} mt-8 sm:mt-16 grid gap-y-5 sm:gap-y-8 justify-center px-5`}
          ref={agendaListRef}
        >
          {agendaData.map((item) => {
            return (

                  <CardTime
                    title={item.title}
                    time={item.time}
                    copy={item.copy}
                  />

            );
          })}

      </Container>

  );
}


code:
import Image from "next/image";
import Container from "../Container";
import AwardFirst from "@/app/components/icons/AwardFirst";
import AwardSecond from "@/app/components/icons/AwardSecond";
import AwardThird from "@/app/components/icons/AwardThird";
import AwardFourth from "@/app/components/icons/AwardFourth";

export default function Awards() {
  return (

      <Container className="pt-12 pb-10 px-6 xs:px-8 bg-gradient-to-b from-primary to-primary-darker shadow-awards rounded-2xl max-w-screen-xl mx-auto">
        <hgroup className="text-center">

            Premios

            Estamos encantados de reconocer a los destacados participantes que
            aportaran pasión, habilidad y deportividad al Torneo de las Fresas.

        </hgroup>

            Categoria Libre

              $8,000 para el campeon

              <AwardFirst />

              $4,000 para el subcampeon

              <AwardSecond />

              $2,000 para el tercer lugar

              <AwardThird />

              $1,000 para el cuarto lugar

              <AwardFourth />

            Categoria 50 y más

              Raqueta Head para el primer lugar

              <Image
                src={"/raqueta.png"}
                width={150}
                height={150}
                alt="Raqueta Head"
                className="max-w-[150px]"
              />

              Maletero MasterPro para el segundo lugar

              <Image
                src={"/maletero.webp"}
                width={150}
                height={150}
                alt="Maletero"
                className="max-w-[150px]"
              />

              Playeras conmemorativas para el tercer lugar

              <Image
                src={"/playeras.png"}
                width={150}
                height={150}
                alt="Raqueta Head"
                className="max-w-[150px]"
              />

      </Container>

  );
}


code:
import Image from "next/image";
import Container from "../Container";
import Link from "next/link";

export default function Footer() {
  return (

      <Container className="flex flex-col gap-y-5 md:flex-row md:justify-between items-center">

          <Link href={"/"}>
            <Image
              src={"/logo.png"}
              width={684}
              height={684}
              alt="Logo TDLF-2025"
              className="max-w-[80px]"
            />
          </Link>

TDLF-2025

            23 de Marzo 2025

            Si quieres contactar escribe al numero{" "}

              462-288-3931

            Desarrollado con ❤ by Ricardo, Francisco, Juan

      </Container>

  );
}


code:
import styles from "@/app/styles/landing.module.css";

const navLinks = [
  {
    text: "Reglas",
    href: "#reglas",
  },
  {
    text: "Agenda",
    href: "#agenda",
  },
  {
    text: "Patrocinadores",
    href: "#patrocinadores",
  },
  {
    text: "Premios",
    href: "#premios",
  },
];

export default function Header() {
  return (
    <header
      className={`${styles.scroll__animate} sticky z-50 py-5 top-4 animate-scroll-header`}
    >

          {navLinks.map((navLink) => {
            return (

                  {navLink.text}

            );
          })}

  );
}


code:
import Image from "next/image";
import SquareBackground from "@/app/components/SquareBackground";

export default function Hero() {
  return (

      <SquareBackground />

        <Image
          src={"/logo.png"}
          width={684}
          height={684}
          alt="Logo TDLF-2025"
          className="max-w-[190px] xs:max-w-[220px] sm:max-w-[280px] blur-lg absolute top-0 left-0"
        />
        <Image
          src={"/logo.png"}
          width={684}
          height={684}
          alt="Logo TDLF-2025"
          className="max-w-[190px] xs:max-w-[220px] sm:max-w-[280px] relative"
        />

            Torneo de las{" "}
            Fresas

            Tercera edición - 2025

  );
}


code:
import { Container, PlayCards } from "@/app/components/landing";
import Image from "next/image";
export default function HowToPlay() {
  return (

      <Container>
        <hgroup className="text-center max-w-5xl mx-auto">

            Así se jugará

            Prepárate para{" "}

              la tercera edición del Torneo de las Fresas
            {" "}
            la competencia de frontenis que te hará sudar y disfrutar al máximo.
            A continuación, te presentamos{" "}
            las reglas oficiales para
            que puedas ir calentando y preparando tu estrategia

        </hgroup>

          <picture className="my-10 w-full inline-block p-6 bg-dark border border-dotted border-neutral-700/80 max-w-md lg:max-w-2xl">
            <Image
              src={"/como-jugar.png"}
              alt="Match de TDLF-2024"
              width={630}
              height={425}
              className="w-full h-full object-cover"
            />
          </picture>

        <PlayCards />
      </Container>

  );
}


code:
import { Container, BentoCard } from "@/app/components/landing";
import Image from "next/image";

export default function NeedToKnow() {
  return (
    <Container className="mt-32">

          Lo que necesitas saber

          <BentoCard className="relative col-span-full flex flex-col gap-3 justify-between items-center lg:col-span-5 xs:gap-0 xs:flex-row">

              Dos
              Categorias

            <Image
              src={"/raqueta.png"}
              alt="Raqueta de Frontenis"
              width={263}
              height={263}
              className="w-full h-full object-cover max-w-[140px] lg:max-w-[180px]"
            />
          </BentoCard>
          <BentoCard className="col-span-full relative lg:col-span-5">
            <Image
              src={"/categoria.png"}
              alt="Raqueta tomada por un jugador"
              width={263}
              height={263}
              className="max-w-[180px] sm:max-w-[220px] absolute -left-10 top-0 xl:max-w-none xl:left-0"
            />

                  <svg
                    xmlns="http://www.w3.org/2000/svg"
                    width="32"
                    height="32"
                    viewBox="0 0 24 24"
                  >
                    <path
                      fill="currentColor"
                      d="M21 9a1 1 0 0 1 1 1a1 1 0 0 1-1 1h-4.47l-.13 1.21l-2.2 4.94c-.2.5-.73.85-1.34.85H8.5c-.8 0-1.5-.73-1.5-1.5V10c0-.39.16-.74.43-1l4.2-4.9l.77.74c.2.19.32.45.32.74l-.03.22L11 9zM2 18v-8h3v8z"
                    />
                  </svg>

                  Libre

                  <svg
                    xmlns="http://www.w3.org/2000/svg"
                    width="32"
                    height="32"
                    viewBox="0 0 24 24"
                  >
                    <path
                      fill="currentColor"
                      d="M21 9a1 1 0 0 1 1 1a1 1 0 0 1-1 1h-4.47l-.13 1.21l-2.2 4.94c-.2.5-.73.85-1.34.85H8.5c-.8 0-1.5-.73-1.5-1.5V10c0-.39.16-.74.43-1l4.2-4.9l.77.74c.2.19.32.45.32.74l-.03.22L11 9zM2 18v-8h3v8z"
                    />
                  </svg>

                  50 y más

          </BentoCard>
          <BentoCard className="flex flex-col-reverse items-center pb-0 col-span-full row-start-1 relative lg:col-span-6 lg:row-start-2 md:pb-10">
            <Image
              src={"/inscripcion.png"}
              alt="Jugadores jugando"
              width={240}
              height={315}
              className="max-w-[120px] xs:max-w-[150px] md:absolute md:bottom-0 md:right-0"
            />

                Inscripción

                  El costo de la inscripción por persona es de{" "}
                  $350 MXN

Incluye zona de refrigerios y comida

          </BentoCard>
          <BentoCard className="col-span-full md:col-span-6 row-span-2 lg:col-span-4 lg:row-start-2">

Grupos y Parejas

                El número de parejas proyectadas (esto puede cambiar) en la
                categoria libre será de 24. Teniendo 6 grupos con 4 parejas cada
                uno.

                El número de parejas proyectadas (esto puede cambiar) en la
                categoria de 50 y más sera de 12. Teniendo 4 grupos con 3
                parejas cada uno.

            <Image
              src={"/pelotas.png"}
              alt="Pelotas de Frontenis"
              width={270}
              height={225}
              className="max-w-[180px] mx-auto"
            />
          </BentoCard>
          <BentoCard className="col-span-full md:col-span-4 lg:col-span-6">

Cancha y Pelotas

                El número de canchas destinadas para los partidos serán 3.

                La pelota del torneo será HEAD o MasterPro Pre-Olímpico, sin
                embargo se hace la petición a cada pareja de llevar una bola.

          </BentoCard>

    </Container>
  );
}


code:
import { Merch, Container } from "@/app/components/landing";
import Image from "next/image";

export default function PreFooter() {
  return (

      <Container>

            La tercera edicion esta aqui

            ¡Vuelve el torneo donde la comunidad de frontenistas se reune!

          <Image
            src={"/tdlf-2024.png"}
            width={1024}
            height={820}
            alt="TDLF-2024"
            className="mt-16 mb-5 w-full h-full max-w-[380px] sm:max-w-[500px] object-cover mx-auto"
          />

            No puedes dejar pasar la oportunidad de lucir tu pasión por este
            emocionante deporte. Te invitamos a adquirir nuestra merch oficial:
            ¡playeras y gorras diseñadas especialmente para este evento!

        <Merch />
      </Container>

  );
}


code:
import Container from "../Container";
import Image from "next/image";
import sponsorsData from "@/app/data/sponsors.json";

export default function Sponsors() {
  return (

      <Container>
        <hgroup className="text-center max-w-4xl mx-auto">

            Patrocinadores

            Agradecemos la confianza de los que hacen que este proyecto se lleve
            a cabo.

        </hgroup>

          {sponsorsData.map((sponsor) => {
            return (

                <a
                  href={sponsor.href}
                  target="_blank"
                  rel="noopener noreferrer"
                  className="min-w-[200px] max-h-40 aspect-square px-8 py-10 w-full relative flex justify-center items-center overflow-hidden rounded-xl group transition-all before:w-full before:h-[1px] before:bottom-0 before:left-0 before:absolute before:bg-gradient-to-r before:from-transparent before:via-midu-primary before:to-transparent before:scale-x-0 hover:before:scale-x-100 before:transition-all before:opacity-0 hover:before:opacity-100 before:duration-500 after:w-full after:h-1/2 after:rounded-[50%] after:left-0 after:bottom-0 after:absolute after:-z-10 after:bg-[radial-gradient(#E61357_0%,transparent_80%)] after:opacity-0 after:blur-lg hover:after:opacity-50 after:transition-all after:duration-500 after:translate-y-full hover:after:translate-y-1/2 max-w-80"
                  title={sponsor.name}
                >
                  <Image
                    src={sponsor.image}
                    width={300}
                    height={150}
                    alt={`Logo ${sponsor.name}`}
                    className="max-w-full"
                  />

            );
          })}

      </Container>

  );
}


code:
"use client"

import * as React from "react"
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"

import { cn } from "@/app/lib/utils"
import { buttonVariants } from "@/app/components/ui/button"

function AlertDialog({
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
  return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
}

function AlertDialogTrigger({
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
  return (
    <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
  )
}

function AlertDialogPortal({
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
  return (
    <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
  )
}

function AlertDialogOverlay({
  className,
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
  return (
    <AlertDialogPrimitive.Overlay
      data-slot="alert-dialog-overlay"
      className={cn(
        "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
        className
      )}
      {...props}
    />
  )
}

function AlertDialogContent({
  className,
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
  return (
    <AlertDialogPortal>
      <AlertDialogOverlay />
      <AlertDialogPrimitive.Content
        data-slot="alert-dialog-content"
        className={cn(
          "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
          className
        )}
        {...props}
      />
    </AlertDialogPortal>
  )
}

function AlertDialogHeader({
  className,
  ...props
}: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="alert-dialog-header"
      className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
      {...props}
    />
  )
}

function AlertDialogFooter({
  className,
  ...props
}: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="alert-dialog-footer"
      className={cn(
        "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
        className
      )}
      {...props}
    />
  )
}

function AlertDialogTitle({
  className,
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
  return (
    <AlertDialogPrimitive.Title
      data-slot="alert-dialog-title"
      className={cn("text-lg font-semibold", className)}
      {...props}
    />
  )
}

function AlertDialogDescription({
  className,
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
  return (
    <AlertDialogPrimitive.Description
      data-slot="alert-dialog-description"
      className={cn("text-muted-foreground text-sm", className)}
      {...props}
    />
  )
}

function AlertDialogAction({
  className,
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {
  return (
    <AlertDialogPrimitive.Action
      className={cn(buttonVariants(), className)}
      {...props}
    />
  )
}

function AlertDialogCancel({
  className,
  ...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {
  return (
    <AlertDialogPrimitive.Cancel
      className={cn(buttonVariants({ variant: "outline" }), className)}
      {...props}
    />
  )
}

export {
  AlertDialog,
  AlertDialogPortal,
  AlertDialogOverlay,
  AlertDialogTrigger,
  AlertDialogContent,
  AlertDialogHeader,
  AlertDialogFooter,
  AlertDialogTitle,
  AlertDialogDescription,
  AlertDialogAction,
  AlertDialogCancel,
}


code:
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { ChevronRight, MoreHorizontal } from "lucide-react"

import { cn } from "@/app/lib/utils"

function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
  return
}

function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
  return (

  )
}

function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
  return (

  )
}

function BreadcrumbLink({
  asChild,
  className,
  ...props
}: React.ComponentProps<"a"> & {
  asChild?: boolean
}) {
  const Comp = asChild ? Slot : "a"

  return (
    <Comp
      data-slot="breadcrumb-link"
      className={cn("hover:text-foreground transition-colors", className)}
      {...props}
    />
  )
}

function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
  return (

  )
}

function BreadcrumbSeparator({
  children,
  className,
  ...props
}: React.ComponentProps<"li">) {
  return (

svg]:size-3.5", className)}
      {...props}
    >
      {children ?? <ChevronRight />}

  )
}

function BreadcrumbEllipsis({
  className,
  ...props
}: React.ComponentProps<"span">) {
  return (

      <MoreHorizontal className="size-4" />
      More

  )
}

export {
  Breadcrumb,
  BreadcrumbList,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbPage,
  BreadcrumbSeparator,
  BreadcrumbEllipsis,
}


code:
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/app/lib/utils"

const buttonVariants = cva(
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
  {
    variants: {
      variant: {
        default:
          "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
        destructive:
          "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
        outline:
          "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
        secondary:
          "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        link: "text-primary underline-offset-4 hover:underline",
      },
      size: {
        default: "h-9 px-4 py-2 has-[>svg]:px-3",
        sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
        lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
        icon: "size-9",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

function Button({
  className,
  variant,
  size,
  asChild = false,
  ...props
}: React.ComponentProps<"button"> &
  VariantProps<typeof buttonVariants> & {
    asChild?: boolean
  }) {
  const Comp = asChild ? Slot : "button"

  return (
    <Comp
      data-slot="button"
      className={cn(buttonVariants({ variant, size, className }))}
      {...props}
    />
  )
}

export { Button, buttonVariants }


code:
"use client"

import * as React from "react"
import { Command as CommandPrimitive } from "cmdk"
import { SearchIcon } from "lucide-react"

import { cn } from "@/app/lib/utils"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "@/app/components/ui/dialog"

function Command({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive>) {
  return (
    <CommandPrimitive
      data-slot="command"
      className={cn(
        "bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
        className
      )}
      {...props}
    />
  )
}

function CommandDialog({
  title = "Command Palette",
  description = "Search for a command to run...",
  children,
  ...props
}: React.ComponentProps<typeof Dialog> & {
  title?: string
  description?: string
}) {
  return (
    <Dialog {...props}>
      <DialogHeader className="sr-only">
        <DialogTitle>{title}</DialogTitle>
        <DialogDescription>{description}</DialogDescription>
      </DialogHeader>
      <DialogContent className="overflow-hidden p-0">
        <Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
          {children}
        </Command>
      </DialogContent>
    </Dialog>
  )
}

function CommandInput({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Input>) {
  return (
    <div
      data-slot="command-input-wrapper"
      className="flex h-9 items-center gap-2 border-b px-3"
    >
      <SearchIcon className="size-4 shrink-0 opacity-50" />
      <CommandPrimitive.Input
        data-slot="command-input"
        className={cn(
          "placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
          className
        )}
        {...props}
      />
    </div>
  )
}

function CommandList({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.List>) {
  return (
    <CommandPrimitive.List
      data-slot="command-list"
      className={cn(
        "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
        className
      )}
      {...props}
    />
  )
}

function CommandEmpty({
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
  return (
    <CommandPrimitive.Empty
      data-slot="command-empty"
      className="py-6 text-center text-sm"
      {...props}
    />
  )
}

function CommandGroup({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Group>) {
  return (
    <CommandPrimitive.Group
      data-slot="command-group"
      className={cn(
        "text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium",
        className
      )}
      {...props}
    />
  )
}

function CommandSeparator({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Separator>) {
  return (
    <CommandPrimitive.Separator
      data-slot="command-separator"
      className={cn("bg-border -mx-1 h-px", className)}
      {...props}
    />
  )
}

function CommandItem({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Item>) {
  return (
    <CommandPrimitive.Item
      data-slot="command-item"
      className={cn(
        "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
        className
      )}
      {...props}
    />
  )
}

function CommandShortcut({
  className,
  ...props
}: React.ComponentProps<"span">) {
  return (
    <span
      data-slot="command-shortcut"
      className={cn(
        "text-muted-foreground ml-auto text-xs tracking-widest",
        className
      )}
      {...props}
    />
  )
}

export {
  Command,
  CommandDialog,
  CommandInput,
  CommandList,
  CommandEmpty,
  CommandGroup,
  CommandItem,
  CommandShortcut,
  CommandSeparator,
}