289 lines
9.0 KiB
TypeScript
289 lines
9.0 KiB
TypeScript
'use client';
|
|
import {
|
|
CalendarBody,
|
|
CalendarDate,
|
|
CalendarDatePagination,
|
|
CalendarDatePicker,
|
|
CalendarHeader,
|
|
CalendarMonthPicker,
|
|
CalendarProvider,
|
|
CalendarYearPicker,
|
|
type Feature,
|
|
} from '@/components/kibo-ui/calendar';
|
|
import {
|
|
AlertDialog,
|
|
AlertDialogAction,
|
|
AlertDialogCancel,
|
|
AlertDialogContent,
|
|
AlertDialogDescription,
|
|
AlertDialogFooter,
|
|
AlertDialogHeader,
|
|
AlertDialogTitle,
|
|
} from '@/components/ui/alert-dialog';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import { useMemo, useState } from 'react';
|
|
import { toast } from 'sonner';
|
|
import {
|
|
changeBaldinhoDaysSale,
|
|
changeBaldinhoDeliverySize,
|
|
changeNoDelivery,
|
|
} from '../action/update-baldinho';
|
|
import { type GetBladinhoResponse } from '../data-access/calendario/get-bladinho';
|
|
|
|
interface PaginaProps {
|
|
bladinhoData: GetBladinhoResponse[];
|
|
}
|
|
|
|
// Componente customizado para exibir informações em múltiplas linhas
|
|
const CustomCalendarItem = ({ feature }: { feature: Feature }) => {
|
|
const lines = feature.name.split('\n');
|
|
return (
|
|
<div className="flex items-start gap-2">
|
|
<div
|
|
className="h-2 w-2 shrink-0 rounded-full mt-1"
|
|
style={{
|
|
backgroundColor: feature.status.color,
|
|
}}
|
|
/>
|
|
<div className="flex flex-col gap-0.5 min-w-0">
|
|
{lines.map((line, index) => (
|
|
<span key={index} className="text-xs leading-tight break-words">
|
|
{line}
|
|
</span>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const Pagina = ({ bladinhoData }: PaginaProps) => {
|
|
// Estado para controlar a abertura do AlertDialog
|
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
// Estado para armazenar a data e o novo valor de delivery quando o usuário clicar
|
|
const [pendingUpdate, setPendingUpdate] = useState<{
|
|
date: Date;
|
|
delivery: boolean;
|
|
} | null>(null);
|
|
|
|
// Transforma os dados do bladinho em features do calendário
|
|
|
|
const [valorBaldinho, setValorBaldinho] = useState<number | undefined>(
|
|
bladinhoData[0].deliverySize ?? 0
|
|
);
|
|
const [diasBaldinho, setDiasBaldinho] = useState<number | undefined>(
|
|
bladinhoData[0].daysSale ?? 0
|
|
);
|
|
const [isLoadingDaysSale, setIsLoadingDaysSale] = useState(false);
|
|
const [isLoadingDeliverySize, setIsLoadingDeliverySize] = useState(false);
|
|
|
|
const features = useMemo<Feature[]>(() => {
|
|
return bladinhoData.map((item) => {
|
|
const dateDelivery = new Date(item.dateDelivery);
|
|
const additionalInfo = [
|
|
`Capacidade: ${item.deliverySize}`,
|
|
`Peso Venda: ${item.saleWeight}`,
|
|
`Disponível: ${item.avaliableDelivery}`,
|
|
].join('\n');
|
|
|
|
return {
|
|
id: item.id.toString(),
|
|
name: additionalInfo,
|
|
startAt: dateDelivery,
|
|
endAt: dateDelivery,
|
|
status: {
|
|
id: item.id.toString(),
|
|
name: item.delivery ? 'Delivery' : 'No Delivery',
|
|
color: item.delivery ? '#6B7280' : '#EF4444',
|
|
},
|
|
isSelected: !item.delivery,
|
|
delivery: item.delivery,
|
|
} as Feature & { delivery: boolean };
|
|
});
|
|
}, [bladinhoData]);
|
|
|
|
const selectedFeatures = useMemo(() => features, [features]);
|
|
|
|
const earliestYear = useMemo(
|
|
() =>
|
|
selectedFeatures
|
|
.map((feature) => feature.startAt.getFullYear())
|
|
.sort()
|
|
.at(0) ?? new Date().getFullYear(),
|
|
[selectedFeatures]
|
|
);
|
|
|
|
const latestYear = useMemo(
|
|
() =>
|
|
selectedFeatures
|
|
.map((feature) => feature.endAt.getFullYear())
|
|
.sort()
|
|
.at(-1) ?? new Date().getFullYear(),
|
|
[selectedFeatures]
|
|
);
|
|
|
|
const handleDateClick = (date: Date, dayFeatures?: Feature[]) => {
|
|
// Encontra o feature correspondente à data clicada
|
|
const featureForDate = dayFeatures?.find((feature) => {
|
|
const featureDate = new Date(feature.startAt);
|
|
return (
|
|
featureDate.getDate() === date.getDate() &&
|
|
featureDate.getMonth() === date.getMonth() &&
|
|
featureDate.getFullYear() === date.getFullYear()
|
|
);
|
|
});
|
|
|
|
let newDelivery: boolean;
|
|
if (featureForDate) {
|
|
// Extrai o isSelected atual do feature
|
|
const currentIsSelected = featureForDate.isSelected ?? false;
|
|
// Inverte o valor para obter o novo delivery (!isSelected)
|
|
newDelivery = !currentIsSelected;
|
|
} else {
|
|
// Se não há feature para esta data, cria um novo com delivery = true
|
|
newDelivery = true;
|
|
}
|
|
|
|
// Armazena os dados e abre o dialog
|
|
setPendingUpdate({ date, delivery: newDelivery });
|
|
setIsDialogOpen(true);
|
|
};
|
|
|
|
const handleConfirmUpdate = async () => {
|
|
if (pendingUpdate) {
|
|
// Executa o update apenas quando o usuário confirmar
|
|
await changeNoDelivery(pendingUpdate.date, pendingUpdate.delivery);
|
|
// Fecha o dialog e limpa o estado
|
|
setIsDialogOpen(false);
|
|
setPendingUpdate(null);
|
|
}
|
|
};
|
|
|
|
const handleCancelUpdate = () => {
|
|
// Apenas fecha o dialog e limpa o estado, sem fazer update
|
|
setIsDialogOpen(false);
|
|
setPendingUpdate(null);
|
|
};
|
|
|
|
const handleBaldinhoDaysSaleChange = async (daysSale: number) => {
|
|
if ((daysSale ?? 0) <= 0) {
|
|
toast.error('O valor deve ser maior que zero');
|
|
return;
|
|
}
|
|
|
|
setDiasBaldinho(daysSale);
|
|
setIsLoadingDaysSale(true);
|
|
|
|
const toastId = toast.loading('Atualizando dias baldinho...');
|
|
|
|
try {
|
|
await changeBaldinhoDaysSale(daysSale);
|
|
toast.success(`Dias baldinho atualizado para ${daysSale}`, {
|
|
id: toastId,
|
|
});
|
|
} catch (error) {
|
|
toast.error('Erro ao atualizar dias baldinho', { id: toastId });
|
|
} finally {
|
|
setIsLoadingDaysSale(false);
|
|
}
|
|
};
|
|
|
|
const handleBaldinhoDeliverySizeChange = async (deliverySize: number) => {
|
|
if ((deliverySize ?? 0) <= 0) {
|
|
toast.error('O valor deve ser maior que zero');
|
|
return;
|
|
}
|
|
|
|
setValorBaldinho(deliverySize);
|
|
setIsLoadingDeliverySize(true);
|
|
|
|
const toastId = toast.loading('Atualizando capacidade baldinho...');
|
|
|
|
try {
|
|
await changeBaldinhoDeliverySize(deliverySize);
|
|
toast.success(`Capacidade baldinho atualizada para ${deliverySize}`, {
|
|
id: toastId,
|
|
});
|
|
} catch (error) {
|
|
toast.error('Erro ao atualizar capacidade baldinho', { id: toastId });
|
|
} finally {
|
|
setIsLoadingDeliverySize(false);
|
|
}
|
|
};
|
|
return (
|
|
<AlertDialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
|
|
<CalendarProvider>
|
|
<CalendarDate>
|
|
<CalendarDatePicker>
|
|
<div className="flex flex-row gap-2">
|
|
<CalendarMonthPicker />
|
|
<CalendarYearPicker end={latestYear} start={earliestYear} />
|
|
<div className="flex flex-row gap-2 items-center">
|
|
<Label className="text-sm min-w-32">Capacidade</Label>
|
|
<Input
|
|
type="number"
|
|
value={valorBaldinho}
|
|
onChange={(e) => setValorBaldinho(Number(e.target.value))}
|
|
/>
|
|
<Button
|
|
type="button"
|
|
onClick={() =>
|
|
handleBaldinhoDeliverySizeChange(valorBaldinho ?? 0)
|
|
}
|
|
disabled={isLoadingDeliverySize}
|
|
>
|
|
{isLoadingDeliverySize ? 'Salvando...' : 'Salvar'}
|
|
</Button>
|
|
</div>
|
|
<div className="flex flex-row gap-2 items-center">
|
|
<Label className="text-sm min-w-32">Dias úteis</Label>
|
|
<Input
|
|
type="number"
|
|
value={diasBaldinho}
|
|
onChange={(e) => setDiasBaldinho(Number(e.target.value))}
|
|
/>
|
|
<Button
|
|
type="button"
|
|
onClick={() =>
|
|
handleBaldinhoDaysSaleChange(diasBaldinho ?? 0)
|
|
}
|
|
disabled={isLoadingDaysSale}
|
|
>
|
|
{isLoadingDaysSale ? 'Salvando...' : 'Salvar'}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</CalendarDatePicker>
|
|
<CalendarDatePagination />
|
|
</CalendarDate>
|
|
<CalendarHeader />
|
|
<CalendarBody features={selectedFeatures} onDateClick={handleDateClick}>
|
|
{({ feature }) => (
|
|
<CustomCalendarItem feature={feature} key={feature.id} />
|
|
)}
|
|
</CalendarBody>
|
|
</CalendarProvider>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>Confirmar alteração</AlertDialogTitle>
|
|
<AlertDialogDescription>
|
|
Tem certeza que deseja alterar o status de entrega para esta data?
|
|
Esta ação não pode ser desfeita.
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel onClick={handleCancelUpdate}>
|
|
Cancelar
|
|
</AlertDialogCancel>
|
|
<AlertDialogAction onClick={handleConfirmUpdate}>
|
|
Confirmar
|
|
</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
);
|
|
};
|
|
|
|
export default Pagina;
|