working team update/create (still need enroll)

This commit is contained in:
yohlo
2025-09-16 13:24:39 -05:00
parent cde74a04d5
commit c170e1e1fe
16 changed files with 845 additions and 175 deletions

View File

@@ -1,56 +1,149 @@
import { SlidePanelField } from "@/components/sheet/slide-panel";
import { Stack, Text } from "@mantine/core";
import { Stack, Text, Group, Avatar } from "@mantine/core";
import { UseFormReturnType } from "@mantine/form";
import { TeamInput } from "../../types";
import { useEffect, useState } from "react";
import { useMemo } from "react";
import { SpotifyTrack } from "@/lib/spotify/types";
import SongSearch from "./song-search";
import DurationPicker from "./duration-picker";
import SongSummary from "./song-summary";
import { MusicNote } from "@phosphor-icons/react/dist/ssr";
interface Song {
song_id: string;
song_name: string;
song_artist: string;
song_album: string;
song_year?: number;
song_start?: number;
song_end?: number;
song_image_url: string;
}
interface SongPickerProps {
form: UseFormReturnType<TeamInput>
form: UseFormReturnType<TeamInput>;
error?: string;
}
const SongPicker = ({ form }: SongPickerProps) => {
const [song, setSong] = useState<Song>();
useEffect(() => {
const SongPicker = ({ form, error }: SongPickerProps) => {
const currentSong = useMemo((): Song | undefined => {
const values = form.getValues();
setSong({
song_id: values.song_id || "",
song_name: values.song_name || "",
song_artist: values.song_artist || "",
song_album: values.song_album || "",
song_year: values.song_year,
song_start: values.song_start,
song_end: values.song_end,
song_image_url: values.song_image_url || "",
})
}, []);
if (values.song_id && values.song_name) {
return {
song_id: values.song_id,
song_name: values.song_name,
song_artist: values.song_artist || "",
song_album: values.song_album || "",
song_start: values.song_start,
song_end: values.song_end,
song_image_url: values.song_image_url || "",
};
}
return undefined;
}, [form.values.song_id, form.values.song_name, form.values.song_artist, form.values.song_album, form.values.song_image_url, form.values.song_start, form.values.song_end]);
return (
<SlidePanelField
key={"song-picker"}
value={""}
onChange={console.log}
Component={() => (
<Stack>
<Text>Song picker</Text>
</Stack>
)}
value={currentSong}
formatValue={(song) => <SongSummary song={song} />}
onChange={(updatedSong: Song) => {
if (updatedSong) {
form.setValues({
song_id: updatedSong.song_id,
song_name: updatedSong.song_name,
song_artist: updatedSong.song_artist,
song_album: updatedSong.song_album,
song_start: updatedSong.song_start,
song_end: updatedSong.song_end,
song_image_url: updatedSong.song_image_url,
});
}
}}
error={error}
Component={SongPickerComponent}
componentProps={{ formValues: form.getValues() }}
title={"Select Song"}
label={"Song"}
label={"Walkout Song"}
placeholder={"Select your walkout song"}
/>
);
};
interface SongPickerComponentProps {
value: Song | undefined;
onChange: (song: Song) => void;
formValues: any;
}
const SongPickerComponent = ({ value: song, onChange, formValues }: SongPickerComponentProps) => {
const handleSongSelect = (track: SpotifyTrack) => {
const defaultStart = 0;
const defaultEnd = Math.min(15, Math.floor(track.duration_ms / 1000));
const newSong: Song = {
song_id: track.id,
song_name: track.name,
song_artist: track.artists.map(a => a.name).join(', '),
song_album: track.album.name,
song_image_url: track.album.images[0]?.url || '',
song_start: defaultStart,
song_end: defaultEnd,
};
onChange(newSong);
};
const handleDurationChange = (startSeconds: number, endSeconds: number) => {
if (song) {
onChange({
...song,
song_start: startSeconds,
song_end: endSeconds,
});
}
};
return (
<Stack styles={{ root: { width: '100%' }}}>
<Text size="lg" fw={500}>Search for a Song</Text>
<SongSearch onChange={handleSongSelect} />
<Stack gap="lg" mt="md">
<Group gap="sm">
<Avatar
src={song?.song_image_url || null}
size={60}
radius="md"
bg="transparent"
>
{!song?.song_image_url && <MusicNote size={24} color="var(--mantine-color-dimmed)" />}
</Avatar>
<div>
<Text size="sm" fw={500} c={song?.song_name ? undefined : "dimmed"}>
{song?.song_name || "No song selected"}
</Text>
<Text size="xs" c="dimmed">
{song?.song_artist || "Select a song to see details"}
</Text>
<Text size="xs" c="dimmed">
{song?.song_album || ""}
</Text>
</div>
</Group>
<Stack gap="xs">
<DurationPicker
songDurationMs={180000}
initialStart={song?.song_start || 0}
initialEnd={song?.song_end || 15}
onChange={handleDurationChange}
disabled={!song?.song_id}
/>
</Stack>
</Stack>
</Stack>
);
};
export default SongPicker;