shift
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { Bike, Building2, CircleDot } from 'lucide-react';
|
||||
import { Bike, Building2, CircleDot, Clock } from 'lucide-react';
|
||||
import { errorMessage } from '@/api/client';
|
||||
import { ridersApi, type RiderRosterRow } from '@/api/deliveries';
|
||||
import type { TenantLocation } from '@/api/types';
|
||||
@@ -112,6 +112,43 @@ export function RiderDrawer({ row, owner, branch, onClose }: RiderDrawerProps) {
|
||||
const set = (key: keyof typeof form) => (value: string) =>
|
||||
setForm((prev) => ({ ...prev, [key]: value }));
|
||||
|
||||
/*
|
||||
* Opening a shift window, from inside the form that needs one.
|
||||
*
|
||||
* A rider cannot be hired without a shift, and `ridershifts` could only be
|
||||
* READ until now — so a region that shipped with no rows was a region no
|
||||
* rider could ever be added to. The drawer said "No shifts set up for this
|
||||
* region" and there was nothing anybody could do about it from the product;
|
||||
* it took somebody with database access.
|
||||
*
|
||||
* It sits here rather than on a settings screen because this is where the
|
||||
* wall is hit. A person hiring their first rider in a new city should not
|
||||
* have to find out that shifts are a separate concept somewhere else.
|
||||
*/
|
||||
const [newShift, setNewShift] = useState({ starttime: '09:00', endtime: '17:00' });
|
||||
const setShiftField = (key: keyof typeof newShift) => (value: string) =>
|
||||
setNewShift((prev) => ({ ...prev, [key]: value }));
|
||||
|
||||
const addShift = useMutation({
|
||||
mutationFn: () =>
|
||||
ridersApi.createShift({
|
||||
applocationid,
|
||||
starttime: newShift.starttime.trim(),
|
||||
endtime: newShift.endtime.trim(),
|
||||
}),
|
||||
onSuccess: async (shift) => {
|
||||
setProblem(null);
|
||||
await client.invalidateQueries({ queryKey: queryKeys.insights.riderShifts(applocationid) });
|
||||
// Selected straight away. Somebody who just typed these hours meant to put
|
||||
// this rider on them, and making them open the dropdown to choose the only
|
||||
// option is a step that exists for no reason.
|
||||
if (shift?.shiftid) setForm((prev) => ({ ...prev, shiftid: String(shift.shiftid) }));
|
||||
},
|
||||
onError: (error) => setProblem(errorMessage(error)),
|
||||
});
|
||||
|
||||
const hasNoShifts = !shifts.isLoading && (shifts.data ?? []).length === 0;
|
||||
|
||||
const save = useMutation({
|
||||
mutationFn: () => {
|
||||
const payload = {
|
||||
@@ -267,6 +304,36 @@ export function RiderDrawer({ row, owner, branch, onClose }: RiderDrawerProps) {
|
||||
/>
|
||||
</Field>
|
||||
|
||||
{/* The way out of the dead end. Shown only when the region genuinely has
|
||||
none — a shift creator on a screen that already has shifts is a way
|
||||
to end up with four overlapping windows nobody can tell apart. */}
|
||||
{hasNoShifts && applocationid > 0 ? (
|
||||
<DrawerCard tone="subtle">
|
||||
<Note>
|
||||
No shift windows exist in this region yet, and a rider cannot be hired without
|
||||
one. Set the hours they work — every rider in this region can then be put on it.
|
||||
</Note>
|
||||
<FieldRow>
|
||||
<Field label="Starts" isRequired>
|
||||
<TextField value={newShift.starttime} onChange={setShiftField('starttime')} />
|
||||
</Field>
|
||||
<Field label="Ends" isRequired>
|
||||
<TextField value={newShift.endtime} onChange={setShiftField('endtime')} />
|
||||
</Field>
|
||||
</FieldRow>
|
||||
<DrawerButton
|
||||
label={addShift.isPending ? 'Adding…' : 'Add this shift'}
|
||||
icon={<Clock size={15} />}
|
||||
isDisabled={
|
||||
addShift.isPending ||
|
||||
newShift.starttime.trim() === '' ||
|
||||
newShift.endtime.trim() === ''
|
||||
}
|
||||
onClick={() => addShift.mutate()}
|
||||
/>
|
||||
</DrawerCard>
|
||||
) : null}
|
||||
|
||||
{/* A merchant's rider works out of one of that merchant's branches.
|
||||
A partner's does not — a partner supplies several merchants and is
|
||||
tied to none of their outlets — so the question is only asked
|
||||
|
||||
Reference in New Issue
Block a user