Tech Table & History components completely rewritten & cleaned up. Just need to implement the realtime subscription now.
This commit is contained in:
@ -9,13 +9,10 @@ import {
|
||||
updateUserStatus,
|
||||
type UserWithStatus,
|
||||
} from '@/lib/hooks/status';
|
||||
import {
|
||||
Drawer,
|
||||
DrawerTrigger,
|
||||
Progress,
|
||||
} from '@/components/ui';
|
||||
import { Drawer, DrawerTrigger, Progress } from '@/components/ui';
|
||||
import { toast } from 'sonner';
|
||||
import { HistoryDrawer } from '@/components/status';
|
||||
import type { Profile } from '@/utils/supabase';
|
||||
import type { RealtimeChannel } from '@supabase/supabase-js';
|
||||
|
||||
type TechTableProps = {
|
||||
@ -33,10 +30,10 @@ export const TechTable = ({
|
||||
const [selectedIds, setSelectedIds] = useState<string[]>([]);
|
||||
const [selectAll, setSelectAll] = useState(false);
|
||||
const [statusInput, setStatusInput] = useState('');
|
||||
const [usersWithStatuses, setUsersWithStatuses] = useState<UserWithStatus[]>(initialStatuses);
|
||||
const [selectedHistoryUserId, setSelectedHistoryUserId] = useState('');
|
||||
|
||||
const supabase = createClient();
|
||||
const [usersWithStatuses, setUsersWithStatuses] =
|
||||
useState<UserWithStatus[]>(initialStatuses);
|
||||
const [selectedHistoryUser, setSelectedHistoryUser] =
|
||||
useState<Profile | null>(null);
|
||||
|
||||
const fetchRecentUsersWithStatuses = useCallback(async () => {
|
||||
try {
|
||||
@ -44,7 +41,7 @@ export const TechTable = ({
|
||||
if (!response.success) throw new Error(response.error);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
toast.error(`Error fetching technicians: ${error as Error}`)
|
||||
toast.error(`Error fetching technicians: ${error as Error}`);
|
||||
return [];
|
||||
}
|
||||
}, []);
|
||||
@ -78,19 +75,24 @@ export const TechTable = ({
|
||||
} else {
|
||||
const result = await updateStatuses(selectedIds, statusInput);
|
||||
if (!result.success) throw new Error(result.error);
|
||||
toast.success(`Status updated for ${selectedIds.length} selected users.`);
|
||||
toast.success(
|
||||
`Status updated for ${selectedIds.length} selected users.`,
|
||||
);
|
||||
}
|
||||
setSelectedIds([]);
|
||||
setStatusInput('');
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : String(error);
|
||||
toast.error(`Failed to update status: ${errorMessage}`);
|
||||
}
|
||||
}, [isAuthenticated, statusInput, selectedIds, usersWithStatuses, profile]);
|
||||
}, [isAuthenticated, statusInput, selectedIds]);
|
||||
|
||||
const handleCheckboxChange = (id: string) => {
|
||||
setSelectedIds((prev) =>
|
||||
prev.includes(id) ? prev.filter(prevId => prevId !== id) : [...prev, id]
|
||||
prev.includes(id)
|
||||
? prev.filter((prevId) => prevId !== id)
|
||||
: [...prev, id],
|
||||
);
|
||||
};
|
||||
|
||||
@ -98,7 +100,7 @@ export const TechTable = ({
|
||||
if (selectAll) {
|
||||
setSelectedIds([]);
|
||||
} else {
|
||||
setSelectedIds(usersWithStatuses.map(tech => tech.user.id));
|
||||
setSelectedIds(usersWithStatuses.map((tech) => tech.user.id));
|
||||
}
|
||||
setSelectAll(!selectAll);
|
||||
};
|
||||
@ -106,7 +108,7 @@ export const TechTable = ({
|
||||
useEffect(() => {
|
||||
setSelectAll(
|
||||
selectedIds.length === usersWithStatuses.length &&
|
||||
usersWithStatuses.length > 0
|
||||
usersWithStatuses.length > 0,
|
||||
);
|
||||
}, [selectedIds.length, usersWithStatuses.length]);
|
||||
|
||||
@ -116,9 +118,9 @@ export const TechTable = ({
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
});
|
||||
const day = date.getDate()
|
||||
const day = date.getDate();
|
||||
const month = date.toLocaleString('default', { month: 'long' });
|
||||
return `${time} = ${month} ${day}`;
|
||||
return `${time} - ${month} ${day}`;
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
@ -131,7 +133,10 @@ export const TechTable = ({
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<table className={`w-full text-center border-collapse ${tvMode ? 'text-4xl lg:text-5xl' : 'text-base lg:text-lg'}`}>
|
||||
<table
|
||||
className={`w-full text-center border-collapse \
|
||||
${tvMode ? 'text-4xl lg:text-5xl' : 'text-base lg:text-lg'}`}
|
||||
>
|
||||
<thead>
|
||||
<tr className='bg-muted'>
|
||||
{!tvMode && (
|
||||
@ -150,7 +155,7 @@ export const TechTable = ({
|
||||
<DrawerTrigger className='hover:underline'>
|
||||
Status
|
||||
</DrawerTrigger>
|
||||
<HistoryDrawer user_id='' />
|
||||
<HistoryDrawer />
|
||||
</Drawer>
|
||||
</th>
|
||||
<th className='py-3 px-4 border font-semibold'>Updated At</th>
|
||||
@ -171,7 +176,9 @@ export const TechTable = ({
|
||||
type='checkbox'
|
||||
className='scale-125 cursor-pointer'
|
||||
checked={selectedIds.includes(userWithStatus.user.id)}
|
||||
onChange={() => handleCheckboxChange(userWithStatus.user.id)}
|
||||
onChange={() =>
|
||||
handleCheckboxChange(userWithStatus.user.id)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
)}
|
||||
@ -182,15 +189,12 @@ export const TechTable = ({
|
||||
<Drawer>
|
||||
<DrawerTrigger
|
||||
className='text-left w-full p-2 rounded hover:bg-muted transition-colors'
|
||||
onClick={() => setSelectedHistoryUserId(userWithStatus.user.id)}
|
||||
onClick={() => setSelectedHistoryUser(userWithStatus.user)}
|
||||
>
|
||||
{userWithStatus.status}
|
||||
</DrawerTrigger>
|
||||
{selectedHistoryUserId === userWithStatus.user.id && (
|
||||
<HistoryDrawer
|
||||
key={selectedHistoryUserId}
|
||||
user_id={selectedHistoryUserId}
|
||||
/>
|
||||
{selectedHistoryUser === userWithStatus.user && (
|
||||
<HistoryDrawer user={selectedHistoryUser} />
|
||||
)}
|
||||
</Drawer>
|
||||
</td>
|
||||
@ -201,7 +205,43 @@ export const TechTable = ({
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
{!tvMode && (
|
||||
<div className='mx-auto flex flex-row items-center justify-center py-5 gap-4'>
|
||||
<input
|
||||
autoFocus
|
||||
type='text'
|
||||
placeholder='New Status'
|
||||
className={
|
||||
'min-w-[120px] lg:min-w-[400px] py-2 px-3 rounded-xl \
|
||||
border bg-background lg:text-2xl focus:outline-none \
|
||||
focus:ring-2 focus:ring-primary'
|
||||
}
|
||||
value={statusInput}
|
||||
onChange={(e) => setStatusInput(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
updateStatus().catch((error) => {
|
||||
toast.error(`Failed to update status: ${error as Error}`);
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
type='submit'
|
||||
className={
|
||||
'min-w-[100px] lg:min-w-[160px] py-2 px-4 rounded-xl \
|
||||
text-center font-semibold lg:text-2xl bg-primary \
|
||||
text-primary-foreground hover:bg-primary/90 \
|
||||
transition-colors disabled:opacity-50 \
|
||||
disabled:cursor-not-allowed'
|
||||
}
|
||||
onClick={() => void updateStatus()}
|
||||
disabled={!statusInput.trim()}
|
||||
>
|
||||
Update
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
};
|
||||
|
Reference in New Issue
Block a user