import { type ReactNode, useCallback, useState, useMemo } from 'react'; import { Globe2, Loader2, Lock } from 'lucide-react'; import { type ListFriendsResponse, ShareFriendList } from './ShareFriendList'; import { TransferToTeamList } from './TransferToTeamList'; import { ShareOptionTabs } from './ShareOptionsTab'; import { ShareTeamMemberList, type TeamMemberList, } from './ShareTeamMemberList'; import { ShareSuccess } from './ShareSuccess'; import { useToast } from '../../hooks/use-toast'; import type { AllowedRoadmapVisibility } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal'; import { httpPatch } from '../../lib/http'; import { Modal } from '../Modal'; import { cn } from '../../lib/classname'; import type { UserTeamItem } from '../TeamDropdown/TeamDropdown'; export type OnShareSettingsUpdate = (options: { visibility: AllowedRoadmapVisibility; sharedTeamMemberIds: string[]; sharedFriendIds: string[]; }) => void; type ShareOptionsModalProps = { onClose: () => void; visibility: AllowedRoadmapVisibility; isDiscoverable?: boolean; sharedFriendIds?: string[]; sharedTeamMemberIds?: string[]; teamId?: string; roadmapId?: string; description?: string; onShareSettingsUpdate: OnShareSettingsUpdate; }; export function ShareOptionsModal(props: ShareOptionsModalProps) { const { roadmapId, onClose, isDiscoverable: defaultIsDiscoverable = false, visibility: defaultVisibility, sharedTeamMemberIds: defaultSharedMemberIds = [], sharedFriendIds: defaultSharedFriendIds = [], teamId, onShareSettingsUpdate, description, } = props; const toast = useToast(); const [isLoading, setIsLoading] = useState(false); const [isSettingsUpdated, setIsSettingsUpdated] = useState(false); const [friends, setFriends] = useState([]); const [teams, setTeams] = useState([]); // Using global team members loading state to avoid glitchy UI when switching between teams const [isTeamMembersLoading, setIsTeamMembersLoading] = useState(false); const membersCache = useMemo(() => new Map(), []); const [visibility, setVisibility] = useState(defaultVisibility); const [isDiscoverable, setIsDiscoverable] = useState(defaultIsDiscoverable); const [sharedTeamMemberIds, setSharedTeamMemberIds] = useState( defaultSharedMemberIds ); const [sharedFriendIds, setSharedFriendIds] = useState( defaultSharedFriendIds ); const [selectedTeamId, setSelectedTeamId] = useState(null); const canTransferRoadmap = visibility === 'team' && !teamId; let isUpdateDisabled = false; // Disable update button if there are no friends to share with if (visibility === 'friends' && sharedFriendIds.length === 0) { isUpdateDisabled = true; // Disable update button if there are no team to transfer } else if (canTransferRoadmap && !selectedTeamId) { isUpdateDisabled = true; // Disable update button if there are no members to share with } else if ( visibility === 'team' && teamId && sharedTeamMemberIds.length === 0 ) { isUpdateDisabled = true; } const handleShareChange: OnShareSettingsUpdate = async ({ sharedFriendIds, visibility, sharedTeamMemberIds, }) => { setIsLoading(true); if (visibility === 'friends' && sharedFriendIds.length === 0) { toast.error('Please select at least one friend'); return; } else if ( visibility === 'team' && teamId && sharedTeamMemberIds.length === 0 ) { toast.error('Please select at least one member'); return; } const { response, error } = await httpPatch( `${ import.meta.env.PUBLIC_API_URL }/v1-update-roadmap-visibility/${roadmapId}`, { visibility, sharedFriendIds, sharedTeamMemberIds, isDiscoverable, } ); if (error) { toast.error(error?.message || 'Something went wrong, please try again'); return; } setIsLoading(false); setIsSettingsUpdated(true); onShareSettingsUpdate({ sharedFriendIds, visibility, sharedTeamMemberIds }); }; const handleTransferToTeam = useCallback( async (teamId: string, sharedTeamMemberIds: string[]) => { if (!roadmapId) { return; } setIsLoading(true); const { response, error } = await httpPatch( `${import.meta.env.PUBLIC_API_URL}/v1-transfer-roadmap/${roadmapId}`, { teamId, sharedTeamMemberIds, isDiscoverable, } ); if (error) { setIsLoading(false); toast.error(error?.message || 'Something went wrong, please try again'); return; } window.location.reload(); }, [roadmapId] ); if (isSettingsUpdated) { return ( ); } return ( { if (isLoading) { return; } onClose(); }} wrapperClassName="max-w-3xl" bodyClassName="p-4 flex flex-col min-h-[440px]" >

Update Sharing Settings

Pick and modify who can access this roadmap.

{ setSelectedTeamId(null); if (['me', 'public'].includes(visibility)) { setSharedTeamMemberIds([]); setSharedFriendIds([]); } else if (visibility === 'friends') { setSharedFriendIds( defaultSharedFriendIds.length > 0 ? defaultSharedFriendIds : [] ); } else if (visibility === 'team' && teamId) { setSharedTeamMemberIds( defaultSharedMemberIds?.length > 0 ? defaultSharedMemberIds : [] ); setSharedFriendIds([]); } else { setSharedFriendIds([]); setSharedTeamMemberIds([]); } }} />
{visibility === 'public' && (

Anyone with the link can access.

)} {visibility === 'me' && (

Only you will be able to access.

)} {/* For Personal Roadmap */} {visibility === 'friends' && ( )} {/* For Team Roadmap */} {visibility === 'team' && teamId && ( )} {canTransferRoadmap && ( <> { setSharedTeamMemberIds([]); }} /> {selectedTeamId && ( <>
)} )}
{visibility !== 'me' && ( <>
)}
{canTransferRoadmap && ( { handleTransferToTeam(selectedTeamId!, sharedTeamMemberIds).then( () => null ); }} > {isLoading && } Transfer )} {!canTransferRoadmap && ( { handleShareChange({ visibility, sharedTeamMemberIds: visibility === 'team' ? sharedTeamMemberIds : [], sharedFriendIds: visibility === 'friends' ? sharedFriendIds : [], }); }} > {isLoading && } Update Sharing Settings )}
); } function UpdateAction(props: { onClick: () => void; disabled?: boolean; children: ReactNode; className?: string; }) { const { onClick, disabled, children, className } = props; return ( ); } type DiscoveryCheckboxProps = { isDiscoverable: boolean; setIsDiscoverable: (isDiscoverable: boolean) => void; }; function DiscoveryCheckbox(props: DiscoveryCheckboxProps) { const { isDiscoverable, setIsDiscoverable } = props; return ( ); }