/** * GroupSelectionMenu * * Content rendered inside the SyncPlay bottom sheet (the sheet itself is * owned by SyncPlayButton). Calls `onClose` after successful actions to * dismiss the parent sheet. */ import { Ionicons } from "@expo/vector-icons"; import { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { ActivityIndicator, TouchableOpacity, View } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { Button } from "@/components/Button"; import { Text } from "@/components/common/Text"; import { useSyncPlay } from "@/providers/SyncPlay"; import type { GroupInfoDto } from "@/providers/SyncPlay/types"; interface GroupSelectionMenuProps { onClose: () => void; } export function GroupSelectionMenu({ onClose }: GroupSelectionMenuProps) { const { t } = useTranslation(); const insets = useSafeAreaInsets(); const { isEnabled, groupInfo, canCreateGroups, joinGroup, createGroup, leaveGroup, getGroups, } = useSyncPlay(); const [groups, setGroups] = useState([]); const [isLoading, setIsLoading] = useState(false); const [isCreating, setIsCreating] = useState(false); useEffect(() => { let cancelled = false; (async () => { setIsLoading(true); try { const fetchedGroups = await getGroups(); if (!cancelled) { setGroups(fetchedGroups); } } catch (error) { console.error("Failed to fetch groups", error); } finally { if (!cancelled) { setIsLoading(false); } } })(); return () => { cancelled = true; }; }, [getGroups]); const handleJoinGroup = useCallback( async (groupId: string) => { try { await joinGroup(groupId); onClose(); } catch (error) { console.error("Failed to join group", error); } }, [joinGroup, onClose], ); const handleCreateGroup = useCallback(async () => { setIsCreating(true); try { await createGroup(); onClose(); } catch (error) { console.error("Failed to create group", error); } finally { setIsCreating(false); } }, [createGroup, onClose]); const handleLeaveGroup = useCallback(async () => { try { await leaveGroup(); onClose(); } catch (error) { console.error("Failed to leave group", error); } }, [leaveGroup, onClose]); const containerStyle = { paddingLeft: Math.max(16, insets.left), paddingRight: Math.max(16, insets.right), paddingBottom: Math.max(16, insets.bottom), paddingTop: 8, }; if (isEnabled && groupInfo) { return ( {t("syncplay.title")} {t("syncplay.my_group")} {groupInfo.GroupName} {groupInfo.State} {groupInfo.Participants && groupInfo.Participants.length > 0 && ( {groupInfo.Participants.length} {t("syncplay.members")} )} ); } return ( {t("syncplay.title")} {t("syncplay.join_group")} {isLoading && ( )} {!isLoading && groups.length > 0 && ( {t("syncplay.available_groups")} {groups.map((group, index) => ( group.GroupId && handleJoinGroup(group.GroupId)} className={`flex-row items-center p-4 ${ index < groups.length - 1 ? "border-b border-neutral-700" : "" }`} > {group.GroupName} {group.Participants?.length ?? 0} {t("syncplay.members")} •{" "} {group.State} ))} )} {!isLoading && groups.length === 0 && ( {t("syncplay.available_groups")}: 0{"\n"} {t("syncplay.create_new_group")} )} {canCreateGroups && ( )} ); }