|
- "use client";
-
- import { Box, Button, Grid, Stack, Typography, Select, MenuItem, FormControl, InputLabel } from "@mui/material";
- import { useCallback, useEffect, useState } from "react";
- import { useTranslation } from "react-i18next";
- import { useSession } from "next-auth/react";
- import { SessionWithTokens } from "@/config/authConfig";
- import { fetchStoreLaneSummary, assignByLane, type StoreLaneSummary } from "@/app/api/pickOrder/actions";
- import Swal from "sweetalert2";
- import dayjs from "dayjs";
-
- interface Props {
- onPickOrderAssigned?: () => void;
- onSwitchToDetailTab?: () => void;
- }
-
- const FinishedGoodFloorLanePanel: React.FC<Props> = ({ onPickOrderAssigned, onSwitchToDetailTab }) => {
- const { t } = useTranslation("pickOrder");
- const { data: session } = useSession() as { data: SessionWithTokens | null };
- const currentUserId = session?.id ? parseInt(session.id) : undefined;
-
- const [summary2F, setSummary2F] = useState<StoreLaneSummary | null>(null);
- const [summary4F, setSummary4F] = useState<StoreLaneSummary | null>(null);
- const [isLoadingSummary, setIsLoadingSummary] = useState(false);
- const [isAssigning, setIsAssigning] = useState(false);
- //const [selectedDate, setSelectedDate] = useState<string>("today");
- const [selectedDate, setSelectedDate] = useState<string>("today");
-
- const loadSummaries = useCallback(async () => {
- setIsLoadingSummary(true);
- try {
- // Convert selectedDate to the format needed
- let dateParam: string | undefined;
- if (selectedDate === "today") {
- dateParam = dayjs().format('YYYY-MM-DD');
- } else if (selectedDate === "tomorrow") {
- dateParam = dayjs().add(1, 'day').format('YYYY-MM-DD');
- } else if (selectedDate === "dayAfterTomorrow") {
- dateParam = dayjs().add(2, 'day').format('YYYY-MM-DD');
- }
-
- const [s2, s4] = await Promise.all([
- fetchStoreLaneSummary("2/F", dateParam),
- fetchStoreLaneSummary("4/F", dateParam)
- ]);
- setSummary2F(s2);
- setSummary4F(s4);
- } catch (error) {
- console.error("Error loading summaries:", error);
- } finally {
- setIsLoadingSummary(false);
- }
- }, [selectedDate]);
-
- // 初始化
- useEffect(() => {
- loadSummaries();
- }, [loadSummaries]);
-
- const handleAssignByLane = useCallback(async (
- storeId: string,
- truckDepartureTime: string,
- truckLanceCode: string,
- requiredDate: string
-
- ) => {
- if (!currentUserId) {
- console.error("Missing user id in session");
- return;
- }
- let dateParam: string | undefined;
- if (requiredDate === "today") {
- dateParam = dayjs().format('YYYY-MM-DD');
- } else if (requiredDate === "tomorrow") {
- dateParam = dayjs().add(1, 'day').format('YYYY-MM-DD');
- } else if (requiredDate === "dayAfterTomorrow") {
- dateParam = dayjs().add(2, 'day').format('YYYY-MM-DD');
- }
- setIsAssigning(true);
- try {
- const res = await assignByLane(currentUserId, storeId, truckLanceCode, truckDepartureTime, dateParam);
-
- if (res.code === "SUCCESS") {
- console.log(" Successfully assigned pick order from lane", truckLanceCode);
- window.dispatchEvent(new CustomEvent('pickOrderAssigned'));
- loadSummaries(); // 刷新按钮状态
- onPickOrderAssigned?.();
- onSwitchToDetailTab?.();
- } else if (res.code === "USER_BUSY") {
- Swal.fire({
- icon: "warning",
- title: t("Warning"),
- text: t("You already have a pick order in progess. Please complete it first before taking next pick order."),
- confirmButtonText: t("Confirm"),
- confirmButtonColor: "#8dba00"
- });
- window.dispatchEvent(new CustomEvent('pickOrderAssigned'));
- } else if (res.code === "NO_ORDERS") {
- Swal.fire({
- icon: "info",
- title: t("Info"),
- text: t("No available pick order(s) for this lane."),
- confirmButtonText: t("Confirm"),
- confirmButtonColor: "#8dba00"
- });
- } else {
- console.log("ℹ️ Assignment result:", res.message);
- }
- } catch (error) {
- console.error("❌ Error assigning by lane:", error);
- Swal.fire({
- icon: "error",
- title: t("Error"),
- text: t("Error occurred during assignment."),
- confirmButtonText: t("Confirm"),
- confirmButtonColor: "#8dba00"
- });
- } finally {
- setIsAssigning(false);
- }
- }, [currentUserId, t, selectedDate, onPickOrderAssigned, onSwitchToDetailTab, loadSummaries]);
-
- const getDateLabel = (offset: number) => {
- return dayjs().add(offset, 'day').format('YYYY-MM-DD');
- };
-
- // Flatten rows to create one box per lane
- const flattenRows = (rows: any[]) => {
- const flattened: any[] = [];
- rows.forEach(row => {
- row.lanes.forEach((lane: any) => {
- flattened.push({
- truckDepartureTime: row.truckDepartureTime,
- lane: lane
- });
- });
- });
- return flattened;
- };
-
- return (
- <Box sx={{ mb: 2 }}>
- {/* Date Selector Dropdown */}
- <Box sx={{ maxWidth: 300, mb: 2 }}>
- <FormControl fullWidth size="small">
- <InputLabel id="date-select-label">{t("Select Date")}</InputLabel>
-
- <Select
- labelId="date-select-label"
- id="date-select"
- value={selectedDate}
- label={t("Select Date")}
-
- onChange={(e) => { {
- setSelectedDate(e.target.value);
- loadSummaries();
- }}}
- >
-
- <MenuItem value="today">
- {t("Today")} ({getDateLabel(0)})
- </MenuItem>
- <MenuItem value="tomorrow">
- {t("Tomorrow")} ({getDateLabel(1)})
- </MenuItem>
- <MenuItem value="dayAfterTomorrow">
- {t("Day After Tomorrow")} ({getDateLabel(2)})
- </MenuItem>
- </Select>
-
- </FormControl>
- </Box>
-
- {/* Grid containing both floors */}
- <Grid container spacing={2}>
- {/* 2/F 楼层面板 */}
- <Grid item xs={12}>
- <Stack direction="row" spacing={2} alignItems="flex-start">
- {/* Floor Label */}
- <Typography
- variant="h6"
- sx={{
- fontWeight: 600,
- minWidth: 60,
- pt: 1
- }}
- >
- 2/F
- </Typography>
-
- {/* Content Box */}
- <Box
- sx={{
- border: '1px solid #e0e0e0',
- borderRadius: 1,
- p: 1,
- backgroundColor: '#fafafa',
- flex: 1
- }}
- >
- {isLoadingSummary ? (
- <Typography variant="caption">Loading...</Typography>
- ) : !summary2F?.rows || summary2F.rows.length === 0 ? (
- <Typography
- variant="body2"
- color="text.secondary"
- sx={{
- fontWeight: 600,
- fontSize: '1rem',
- textAlign: 'center',
- py: 1
- }}
- >
- {t("No entries available")}
- </Typography>
- ) : (
- <Grid container spacing={1}>
- {flattenRows(summary2F.rows).map((item, idx) => (
- <Grid item xs={12} sm={6} md={3} key={idx}>
- <Stack
- direction="row"
- spacing={1}
- alignItems="center"
- sx={{
- border: '1px solid #e0e0e0',
- borderRadius: 0.5,
- p: 1,
- backgroundColor: '#fff',
- height: '100%'
- }}
- >
- {/* Time on the left */}
- <Typography
- variant="body2"
- sx={{
- fontWeight: 600,
- fontSize: '1rem',
- minWidth: 50,
- whiteSpace: 'nowrap'
- }}
- >
- {item.truckDepartureTime}
- </Typography>
-
- {/* Single Button on the right */}
- <Button
- variant="outlined"
- size="medium"
- disabled={item.lane.unassigned === 0 || isAssigning}
- onClick={() => handleAssignByLane("2/F", item.truckDepartureTime, item.lane.truckLanceCode, selectedDate)}
- sx={{
- flex: 1,
- fontSize: '1.1rem',
- py: 1,
- px: 1.5,
- borderWidth: 1,
- borderColor: '#ccc',
- fontWeight: 500,
- '&:hover': {
- borderColor: '#999',
- backgroundColor: '#f5f5f5'
- }
- }}
- >
- {`${item.lane.truckLanceCode} (${item.lane.unassigned}/${item.lane.total})`}
- </Button>
- </Stack>
- </Grid>
- ))}
- </Grid>
- )}
- </Box>
- </Stack>
- </Grid>
-
- {/* 4/F 楼层面板 */}
- <Grid item xs={12}>
- <Stack direction="row" spacing={2} alignItems="flex-start">
- {/* Floor Label */}
- <Typography
- variant="h6"
- sx={{
- fontWeight: 600,
- minWidth: 60,
- pt: 1
- }}
- >
- 4/F
- </Typography>
-
- {/* Content Box */}
- <Box
- sx={{
- border: '1px solid #e0e0e0',
- borderRadius: 1,
- p: 1,
- backgroundColor: '#fafafa',
- flex: 1
- }}
- >
- {isLoadingSummary ? (
- <Typography variant="caption">Loading...</Typography>
- ) : !summary4F?.rows || summary4F.rows.length === 0 ? (
- <Typography
- variant="body2"
- color="text.secondary"
- sx={{
- fontWeight: 600,
- fontSize: '1rem',
- textAlign: 'center',
- py: 1
- }}
- >
- {t("No entries available")}
- </Typography>
- ) : (
- <Grid container spacing={1}>
- {flattenRows(summary4F.rows).map((item, idx) => (
- <Grid item xs={12} sm={6} md={3} key={idx}>
- <Stack
- direction="row"
- spacing={1}
- alignItems="center"
- sx={{
- border: '1px solid #e0e0e0',
- borderRadius: 0.5,
- p: 1,
- backgroundColor: '#fff',
- height: '100%'
- }}
- >
- {/* Time on the left */}
- <Typography
- variant="body2"
- sx={{
- fontWeight: 600,
- fontSize: '1rem',
- minWidth: 50,
- whiteSpace: 'nowrap'
- }}
- >
- {item.truckDepartureTime}
- </Typography>
-
- {/* Single Button on the right */}
- <Button
- variant="outlined"
- size="medium"
- disabled={item.lane.unassigned === 0 || isAssigning}
- onClick={() => handleAssignByLane("4/F", item.truckDepartureTime, item.lane.truckLanceCode, selectedDate)}
- sx={{
- flex: 1,
- fontSize: '1.1rem',
- py: 1,
- px: 1.5,
- borderWidth: 1,
- borderColor: '#ccc',
- fontWeight: 500,
- '&:hover': {
- borderColor: '#999',
- backgroundColor: '#f5f5f5'
- }
- }}
- >
- {`${item.lane.truckLanceCode} (${item.lane.unassigned}/${item.lane.total})`}
- </Button>
- </Stack>
- </Grid>
- ))}
- </Grid>
- )}
- </Box>
- </Stack>
- </Grid>
- </Grid>
- </Box>
- );
- };
-
- export default FinishedGoodFloorLanePanel;
|