import { FileInput, Stack, TextInput } from "@mantine/core"; import { useForm, UseFormInput } from "@mantine/form"; import { LinkIcon } from "@phosphor-icons/react"; import SlidePanel from "@/components/sheet/slide-panel"; import { isNotEmpty } from "@mantine/form"; import useCreateTeam from "../../hooks/use-create-team"; import useUpdateTeam from "../../hooks/use-update-team"; import toast from "@/lib/sonner"; import { logger } from "../.."; import { useQueryClient } from "@tanstack/react-query"; import { tournamentKeys } from "@/features/tournaments/queries"; import { useCallback } from "react"; import { TeamInput } from "../../types"; import { teamKeys } from "../../queries"; import SongPicker from "./song-picker"; import PlayersPicker from "./players-picker"; import imageCompression from "browser-image-compression"; interface TeamFormProps { close: () => void; initialValues?: Partial; teamId?: string; tournamentId?: string; onSubmit?: (teamId: string) => void; } const TeamForm = ({ close, initialValues, teamId, tournamentId, onSubmit }: TeamFormProps) => { const isEditMode = !!teamId; const config: UseFormInput = { initialValues: { name: initialValues?.name || "", // primary_color: initialValues?.primary_color, // accent_color: initialValues?.accent_color, song_id: initialValues?.song_id, song_name: initialValues?.song_name, song_artist: initialValues?.song_artist, song_album: initialValues?.song_album, song_start: initialValues?.song_start, song_end: initialValues?.song_end, song_image_url: initialValues?.song_image_url, logo: undefined, players: initialValues?.players || [], }, onSubmitPreventDefault: "always", validate: { name: isNotEmpty("Name is required"), players: (value: string[]) => value.length > 1 && value[1] !== "" ? undefined : "Players are required", song_name: isNotEmpty("Song is required"), song_start: (value, values) => { if (values.song_name && values.song_id) { if (value === undefined || value === null) { return "Song start time is required"; } } return undefined; }, song_end: (value, values) => { if (values.song_name && values.song_id) { if (value === undefined || value === null) { return "Song end time is required"; } if (values.song_start !== undefined && value !== undefined) { const duration = value - values.song_start; if (duration < 10) { return "Song segment must be at least 10 seconds"; } if (duration > 15) { return "Song segment must be no more than 15 seconds"; } } } return undefined; }, }, }; const form = useForm(config); const queryClient = useQueryClient(); const { mutate: createTeam, isPending: createPending } = useCreateTeam(); const { mutate: updateTeam, isPending: updatePending } = useUpdateTeam( teamId! ); const isPending = createPending || updatePending; const handleSubmit = useCallback( async (values: TeamInput) => { const { logo, ...teamData } = values; const mutation = isEditMode ? updateTeam : createTeam; const errorMessage = isEditMode ? "Failed to update team" : "Failed to create team"; mutation(teamData, { onSuccess: async (team: any) => { queryClient.invalidateQueries({ queryKey: teamKeys.list }); queryClient.invalidateQueries({ queryKey: teamKeys.details(team.id), }); if (logo && team) { try { let processedLogo = logo; if (logo.size > 500 * 1024) { const compressionOptions = { maxSizeMB: 0.5, maxWidthOrHeight: 800, useWebWorker: true, fileType: logo.type, }; try { processedLogo = await imageCompression(logo, compressionOptions); logger.info("image compressed", { originalSize: logo.size, compressedSize: processedLogo.size, reduction: ((logo.size - processedLogo.size) / logo.size * 100).toFixed(1) + "%" }); } catch (compressionError) { logger.warn("compression failed, falling back", compressionError); processedLogo = logo; } } const formData = new FormData(); formData.append("teamId", team.id); formData.append("logo", processedLogo); const response = await fetch("/api/teams/upload-logo", { method: "POST", body: formData, }); if (!response.ok) { const error = await response.json(); throw new Error(error.error || "Failed to upload logo"); } const result = await response.json(); queryClient.setQueryData( tournamentKeys.details(result.team!.id), result.team ); } catch (error: any) { const logoErrorMessage = isEditMode ? `Team updated but logo upload failed: ${error.message}` : `Team created but logo upload failed: ${error.message}`; toast.error(logoErrorMessage); logger.error("Team logo upload error", error); } } if (team && team.id) { onSubmit?.(team.id) } close(); }, onError: (error: any) => { toast.error(`${errorMessage}: ${error.message}`); logger.error(`Team ${isEditMode ? "update" : "create"} error`, error); }, }); }, [isEditMode, createTeam, updateTeam, queryClient] ); return ( } {...form.getInputProps("logo")} /> {tournamentId && ( )} {/* ( {value} )} /> ( {value} )} /> */} ); }; export default TeamForm;