diff --git a/src/components/status/List.tsx b/src/components/status/List.tsx index 87bf212..361b41e 100644 --- a/src/components/status/List.tsx +++ b/src/components/status/List.tsx @@ -1,5 +1,6 @@ 'use client'; import { useState, useEffect } from 'react'; +import type React from 'react'; import { useAuth, useTVMode } from '@/components/context'; import type { UserWithStatus } from '@/lib/hooks'; import { BasedAvatar, Drawer, DrawerTrigger, Loading } from '@/components/ui'; @@ -7,11 +8,10 @@ import { StatusMessage, SubmitButton } from '@/components/default'; import { ConnectionStatus, HistoryDrawer } from '@/components/status'; import type { Profile } from '@/utils/supabase'; import { makeConditionalClassName } from '@/lib/utils'; -import { Card, CardContent, CardHeader } from '@/components/ui/card'; -import { Checkbox } from '@/components/ui/checkbox'; +import { Card, CardContent } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; -import { RefreshCw, Clock, Calendar } from 'lucide-react'; +import { RefreshCw, Clock, Calendar, CheckCircle2 } from 'lucide-react'; import { useStatusData, useStatusSubscription } from '@/lib/hooks'; import { formatTime, formatDate } from '@/lib/utils'; import Link from 'next/link'; @@ -43,7 +43,6 @@ export const StatusList = ({ initialStatuses = [] }: ListProps) => { enabled: isAuthenticated, }); - // In your StatusList component const { connectionStatus, connect: reconnect } = useStatusSubscription(() => { refetch().catch((error) => { console.error('Error refetching statuses:', error); @@ -75,7 +74,12 @@ export const StatusList = ({ initialStatuses = [] }: ListProps) => { setUpdateStatusMessage(''); }; - const handleCheckboxChange = (user: UserWithStatus) => { + const handleCardSelect = (user: UserWithStatus, e: React.MouseEvent) => { + // Prevent selection if clicking on profile elements + if ((e.target as HTMLElement).closest('[data-profile-trigger]')) { + return; + } + setSelectedUsers((prev) => prev.some((u) => u.user.id === user.user.id) ? prev.filter((prevUser) => prevUser.user.id !== user.user.id) @@ -121,54 +125,46 @@ export const StatusList = ({ initialStatuses = [] }: ListProps) => { const containerClassName = makeConditionalClassName({ context: tvMode, - defaultClassName: 'flex flex-col mx-auto space-y-4 items-center', - on: 'lg:w-11/12 w-full mt-15', - off: 'sm:w-5/6 md:3/4 lg:w-1/2', + defaultClassName: + 'flex flex-col mx-auto items-center\ + sm:w-5/6 md:w-3/4 lg:w-2/3 xl:w-1/2 min-w-[450px]', + on: 'mt-8', + off: 'px-10', }); const headerClassName = makeConditionalClassName({ context: tvMode, defaultClassName: 'w-full', on: 'hidden', - off: 'flex mb-4 justify-between', + off: 'flex mb-3 justify-between items-center', }); const cardContainerClassName = makeConditionalClassName({ context: tvMode, - defaultClassName: '', - on: '', - off: 'space-y-3 items-center justify-center w-full', - }); - - const cardClassName = makeConditionalClassName({ - context: tvMode, - defaultClassName: - 'transition-all duration-300 hover:shadow-md hover:bg-muted/50 cursor-pointer', - on: 'lg:text-4xl', - off: 'lg:text-base lg:w-full', + defaultClassName: 'w-full space-y-2', }); return (
-
-
- +
+ {selectAll ? 'Deselect All' : 'Select All'} + {!tvMode && ( -
-

Miss the old table?

+
+ Miss the old table? Find it here! @@ -198,88 +194,119 @@ export const StatusList = ({ initialStatuses = [] }: ListProps) => { handleCardSelect(userWithStatus, e)} > - -
-
- {!tvMode && ( - - handleCheckboxChange(userWithStatus) + {isSelected && ( +
+ +
+ )} + + +
+ {/* Profile Section - Clickable for history */} + + +
+ setSelectedHistoryUser(userWithStatus.user) } - onClick={(e) => e.stopPropagation()} - /> - )} - -
-

- {userWithStatus.user.full_name} -

- {isUpdatedByOther && ( -
- +
+ + {selectedHistoryUser === userWithStatus.user && ( + + )} + + + {/* Content Section */} +
+ {/* Header with name and timestamp */} +
+
+ + +

+ setSelectedHistoryUser(userWithStatus.user) + } + > + {userWithStatus.user.full_name} +

+
+ {selectedHistoryUser === userWithStatus.user && ( + + )} +
+
+

{userWithStatus.status}

+
+
+
+
+ - Updated by {userWithStatus.updated_by?.full_name} + {formatTime(userWithStatus.created_at)}
- )} -
-
-
-
- - - {formatTime(userWithStatus.created_at)} - -
-
- - - {formatDate(userWithStatus.created_at)} - +
+ + + {formatDate(userWithStatus.created_at)} + +
+
+ {isUpdatedByOther && ( +
+ + +
+

Updated by

+ {userWithStatus.updated_by?.full_name} +
+
+
+ )} +
+
- - - - -
- setSelectedHistoryUser(userWithStatus.user) - } - > -

{userWithStatus.status}

-
-
- {selectedHistoryUser === userWithStatus.user && ( - - )} -
); @@ -289,7 +316,7 @@ export const StatusList = ({ initialStatuses = [] }: ListProps) => { {usersWithStatuses.length === 0 && (

No status updates have been made in the past day.

@@ -305,8 +332,8 @@ export const StatusList = ({ initialStatuses = [] }: ListProps) => { setStatusInput(e.target.value)} @@ -327,9 +354,8 @@ export const StatusList = ({ initialStatuses = [] }: ListProps) => { className='px-6' > {selectedUsers.length > 0 - ? `Update status for ${selectedUsers.length} - ${selectedUsers.length > 1 ? 'users' : 'user'}` - : 'Update status'} + ? `Update ${selectedUsers.length} ${selectedUsers.length > 1 ? 'users' : 'user'}` + : 'Update Status'}
{updateStatusMessage && @@ -347,7 +373,7 @@ export const StatusList = ({ initialStatuses = [] }: ListProps) => { diff --git a/src/components/status/StatusList.tsx b/src/components/status/StatusList.tsx deleted file mode 100644 index 9148f57..0000000 --- a/src/components/status/StatusList.tsx +++ /dev/null @@ -1,388 +0,0 @@ -'use client'; -import { useState, useEffect } from 'react'; -import type React from 'react'; - -import { useAuth, useTVMode } from '@/components/context'; -import type { UserWithStatus } from '@/lib/hooks'; -import { BasedAvatar, Drawer, DrawerTrigger, Loading } from '@/components/ui'; -import { StatusMessage, SubmitButton } from '@/components/default'; -import { ConnectionStatus, HistoryDrawer } from '@/components/status'; -import type { Profile } from '@/utils/supabase'; -import { makeConditionalClassName } from '@/lib/utils'; -import { Card, CardContent } from '@/components/ui/card'; -import { Input } from '@/components/ui/input'; -import { Button } from '@/components/ui/button'; -import { RefreshCw, Clock, Calendar, CheckCircle2 } from 'lucide-react'; -import { useStatusData, useStatusSubscription } from '@/lib/hooks'; -import { formatTime, formatDate } from '@/lib/utils'; -import Link from 'next/link'; - -type ListProps = { - initialStatuses: UserWithStatus[]; -}; - -export const StatusList = ({ initialStatuses = [] }: ListProps) => { - const { isAuthenticated } = useAuth(); - const { tvMode } = useTVMode(); - - const [selectedUsers, setSelectedUsers] = useState([]); - const [selectAll, setSelectAll] = useState(false); - const [statusInput, setStatusInput] = useState(''); - const [selectedHistoryUser, setSelectedHistoryUser] = - useState(null); - const [updateStatusMessage, setUpdateStatusMessage] = useState(''); - - const { - data: usersWithStatuses = initialStatuses, - isLoading: loading, - error, - refetch, - newStatuses, - updateStatusMutation, - } = useStatusData({ - initialData: initialStatuses, - enabled: isAuthenticated, - }); - - const { connectionStatus, connect: reconnect } = useStatusSubscription(() => { - refetch().catch((error) => { - console.error('Error refetching statuses:', error); - }); - }); - - const handleUpdateStatus = () => { - if (!isAuthenticated) { - setUpdateStatusMessage( - 'Error: You must be signed in to update technician statuses!', - ); - return; - } - - if (statusInput.length < 3 || statusInput.length > 80) { - setUpdateStatusMessage( - 'Error: Your status must be between 3 & 80 characters long!', - ); - return; - } - - updateStatusMutation.mutate({ - usersWithStatuses: selectedUsers, - status: statusInput.trim(), - }); - - setSelectedUsers([]); - setStatusInput(''); - setUpdateStatusMessage(''); - }; - - const handleCardSelect = (user: UserWithStatus, e: React.MouseEvent) => { - // Prevent selection if clicking on profile elements - if ((e.target as HTMLElement).closest('[data-profile-trigger]')) { - return; - } - - setSelectedUsers((prev) => - prev.some((u) => u.user.id === user.user.id) - ? prev.filter((prevUser) => prevUser.user.id !== user.user.id) - : [...prev, user], - ); - }; - - const handleSelectAllChange = () => { - if (selectAll) { - setSelectedUsers([]); - } else { - setSelectedUsers(usersWithStatuses); - } - setSelectAll(!selectAll); - }; - - useEffect(() => { - setSelectAll( - selectedUsers.length === usersWithStatuses.length && - usersWithStatuses.length > 0, - ); - }, [selectedUsers.length, usersWithStatuses.length]); - - if (loading) { - return ( -
- -
- ); - } - - if (error) { - return ( -
-

Error loading status updates

- -
- ); - } - - const containerClassName = makeConditionalClassName({ - context: tvMode, - defaultClassName: 'flex flex-col mx-auto space-y-3 items-center', - on: 'lg:w-11/12 w-full mt-8', - off: 'sm:w-5/6 md:w-3/4 lg:w-2/3 xl:w-1/2', - }); - - const headerClassName = makeConditionalClassName({ - context: tvMode, - defaultClassName: 'w-full', - on: 'hidden', - off: 'flex mb-6 justify-between items-center', - }); - - const cardContainerClassName = makeConditionalClassName({ - context: tvMode, - defaultClassName: 'w-full', - on: 'grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4', - off: 'space-y-2 w-full', - }); - - return ( -
-
-
- - {!tvMode && ( -
- Miss the old table? - - Find it here! - -
- )} -
-
- -
-
- -
- {usersWithStatuses.map((userWithStatus) => { - const isSelected = selectedUsers.some( - (u) => u.user.id === userWithStatus.user.id, - ); - const isNewStatus = newStatuses.has(userWithStatus); - const isUpdatedByOther = - userWithStatus.updated_by && - userWithStatus.updated_by.id !== userWithStatus.user.id; - - return ( - handleCardSelect(userWithStatus, e)} - > - {isSelected && ( -
- -
- )} - - -
- {/* Profile Section - Clickable for history */} - - -
- setSelectedHistoryUser(userWithStatus.user) - } - > - -
-
- {selectedHistoryUser === userWithStatus.user && ( - - )} -
- - {/* Content Section */} -
- {/* Header with name and timestamp */} -
- - -

- setSelectedHistoryUser(userWithStatus.user) - } - > - {userWithStatus.user.full_name} -

-
- {selectedHistoryUser === userWithStatus.user && ( - - )} -
- -
- - - {formatTime(userWithStatus.created_at)} - -
-
- - {/* Status Content */} -
-

{userWithStatus.status}

-
- - {/* Footer with date and updated by info */} -
-
- - - {formatDate(userWithStatus.created_at)} - -
- - {isUpdatedByOther && ( -
- - - Updated by {userWithStatus.updated_by?.full_name} - -
- )} -
-
-
-
-
- ); - })} -
- - {usersWithStatuses.length === 0 && ( - -

- No status updates have been made in the past day. -

-
- )} - - {!tvMode && ( - -
-

Update Status

-
-
- setStatusInput(e.target.value)} - onKeyDown={(e) => { - if ( - e.key === 'Enter' && - !e.shiftKey && - !updateStatusMutation.isPending - ) { - e.preventDefault(); - handleUpdateStatus(); - } - }} - /> - - {selectedUsers.length > 0 - ? `Update ${selectedUsers.length} ${selectedUsers.length > 1 ? 'users' : 'user'}` - : 'Update Status'} - -
- {updateStatusMessage && - (updateStatusMessage.includes('Error') || - updateStatusMessage.includes('error') || - updateStatusMessage.includes('failed') || - updateStatusMessage.includes('invalid') ? ( - - ) : ( - - ))} -
-
- - - - - - -
-
-
- )} -
- ); -}; diff --git a/src/components/status/Table.tsx b/src/components/status/Table.tsx index 6002dc5..50a4856 100644 --- a/src/components/status/Table.tsx +++ b/src/components/status/Table.tsx @@ -139,14 +139,14 @@ export const TechTable = ({ initialStatuses = [] }: TableProps) => { const thClassName = makeConditionalClassName({ context: tvMode, defaultClassName: 'py-4 px-4 border font-semibold ', - on: 'lg:text-6xl xl:min-w-[420px]', - off: 'lg:text-5xl xl:min-w-[300px]', + on: 'lg:text-5xl xl:min-w-[420px]', + off: 'lg:text-4xl xl:min-w-[320px]', }); const tdClassName = makeConditionalClassName({ context: tvMode, defaultClassName: 'py-2 px-2 border', - on: 'lg:text-5xl', - off: 'lg:text-4xl', + on: 'lg:text-4xl', + off: 'lg:text-3xl', }); const tCheckboxClassName = `py-3 px-4 border`; const checkBoxClassName = `lg:scale-200 cursor-pointer`; @@ -161,13 +161,13 @@ export const TechTable = ({ initialStatuses = [] }: TableProps) => { showAsButton={connectionStatus === 'disconnected'} /> {!tvMode && ( -
-

Tired of the old table?

+
+

Tired of the old table?

- Try out the new status list! + Try the new status list!
)} @@ -248,7 +248,7 @@ export const TechTable = ({ initialStatuses = [] }: TableProps) => { fullName={userWithStatus.updated_by?.full_name} className='w-5 h-5' /> - + Updated by {userWithStatus.updated_by.full_name}
diff --git a/src/components/status/index.tsx b/src/components/status/index.tsx index 719a4c5..2bca4d1 100644 --- a/src/components/status/index.tsx +++ b/src/components/status/index.tsx @@ -1,5 +1,4 @@ export * from './ConnectionStatus'; export * from './HistoryDrawer'; -//export * from './List'; -export * from './StatusList'; +export * from './List'; export * from './Table';