|
- "use client";
-
- import React, { useCallback, useEffect, useMemo, useState } from "react";
- import {
- Box,
- Button,
- Dialog,
- DialogActions,
- DialogContent,
- DialogTitle,
- IconButton,
- Stack,
- Table,
- TableBody,
- TableCell,
- TableContainer,
- TableHead,
- TableRow,
- TextField,
- Autocomplete,
- CircularProgress,
- } from "@mui/material";
- import { useTranslation } from "react-i18next";
- import { Add, Delete, Edit } from "@mui/icons-material";
- import SearchBox, { Criterion } from "../SearchBox/SearchBox";
- import SearchResults, { Column } from "../SearchResults/SearchResults";
- import {
- saveQcCategoryQcItemMapping,
- deleteQcCategoryQcItemMapping,
- getQcCategoryQcItemMappings,
- fetchQcCategoriesForAll,
- fetchQcItemsForAll,
- } from "@/app/api/settings/qcItemAll/actions";
- import {
- QcCategoryResult,
- QcItemResult,
- } from "@/app/api/settings/qcItemAll";
- import { QcItemInfo } from "@/app/api/settings/qcItemAll";
- import {
- deleteDialog,
- errorDialogWithContent,
- submitDialog,
- successDialog,
- } from "../Swal/CustomAlerts";
-
- type SearchQuery = Partial<Omit<QcCategoryResult, "id">>;
- type SearchParamNames = keyof SearchQuery;
-
- const Tab1QcCategoryQcItemMapping: React.FC = () => {
- const { t } = useTranslation("qcItemAll");
- const [qcCategories, setQcCategories] = useState<QcCategoryResult[]>([]);
- const [filteredQcCategories, setFilteredQcCategories] = useState<QcCategoryResult[]>([]);
- const [selectedCategory, setSelectedCategory] = useState<QcCategoryResult | null>(null);
- const [mappings, setMappings] = useState<QcItemInfo[]>([]);
- const [openDialog, setOpenDialog] = useState(false);
- const [openAddDialog, setOpenAddDialog] = useState(false);
- const [qcItems, setQcItems] = useState<QcItemResult[]>([]);
- const [selectedQcItem, setSelectedQcItem] = useState<QcItemResult | null>(null);
- const [order, setOrder] = useState<number>(0);
- const [loading, setLoading] = useState(true);
-
- useEffect(() => {
- const loadData = async () => {
- setLoading(true);
- try {
- // Only load categories list (same as Tab 2) - fast!
- const categories = await fetchQcCategoriesForAll();
- setQcCategories(categories || []);
- setFilteredQcCategories(categories || []);
- } catch (error) {
- console.error("Error loading data:", error);
- setQcCategories([]); // Ensure it's always an array
- setFilteredQcCategories([]);
- } finally {
- setLoading(false);
- }
- };
- loadData();
- }, []);
-
- const handleViewMappings = useCallback(async (category: QcCategoryResult) => {
- setSelectedCategory(category);
- // Load mappings when user clicks View (lazy loading)
- const mappingData = await getQcCategoryQcItemMappings(category.id);
- setMappings(mappingData);
- setOpenDialog(true);
- }, []);
-
- const handleAddMapping = useCallback(async () => {
- if (!selectedCategory) return;
- // Load qc items list when opening add dialog
- try {
- const itemsData = await fetchQcItemsForAll();
- setQcItems(itemsData);
- } catch (error) {
- console.error("Error loading qc items:", error);
- }
- setOpenAddDialog(true);
- setOrder(0);
- setSelectedQcItem(null);
- }, [selectedCategory]);
-
- const handleSaveMapping = useCallback(async () => {
- if (!selectedCategory || !selectedQcItem) return;
-
- await submitDialog(async () => {
- try {
- await saveQcCategoryQcItemMapping(
- selectedCategory.id,
- selectedQcItem.id,
- order,
- undefined // No description needed - qcItem already has description
- );
- // Close add dialog first
- setOpenAddDialog(false);
- setSelectedQcItem(null);
- setOrder(0);
- // Reload mappings to update the view
- const mappingData = await getQcCategoryQcItemMappings(selectedCategory.id);
- setMappings(mappingData);
- // Show success message after closing dialogs
- await successDialog(t("Submit Success"), t);
- // Keep the view dialog open to show updated data
- } catch (error) {
- errorDialogWithContent(t("Submit Error"), String(error), t);
- }
- }, t);
- }, [selectedCategory, selectedQcItem, order, t]);
-
- const handleDeleteMapping = useCallback(
- async (mappingId: number) => {
- if (!selectedCategory) return;
-
- deleteDialog(async () => {
- try {
- await deleteQcCategoryQcItemMapping(mappingId);
- await successDialog(t("Delete Success"), t);
- // Reload mappings
- const mappingData = await getQcCategoryQcItemMappings(selectedCategory.id);
- setMappings(mappingData);
- // No need to reload categories list - it doesn't change
- } catch (error) {
- errorDialogWithContent(t("Delete Error"), String(error), t);
- }
- }, t);
- },
- [selectedCategory, t]
- );
-
- const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
- () => [
- { label: t("Code"), paramName: "code", type: "text" },
- { label: t("Name"), paramName: "name", type: "text" },
- ],
- [t]
- );
-
- const onReset = useCallback(() => {
- setFilteredQcCategories(qcCategories);
- }, [qcCategories]);
-
- const columnWidthSx = (width = "10%") => {
- return { width: width, whiteSpace: "nowrap" };
- };
-
- const columns = useMemo<Column<QcCategoryResult>[]>(
- () => [
- { name: "code", label: t("Qc Category Code"), sx: columnWidthSx("20%") },
- { name: "name", label: t("Qc Category Name"), sx: columnWidthSx("40%") },
- {
- name: "id",
- label: t("Actions"),
- onClick: (category) => handleViewMappings(category),
- buttonIcon: <Edit />,
- buttonIcons: {} as any,
- sx: columnWidthSx("10%"),
- },
- ],
- [t, handleViewMappings]
- );
-
- return (
- <Box>
- <SearchBox
- criteria={searchCriteria}
- onSearch={(query) => {
- setFilteredQcCategories(
- qcCategories.filter(
- (qc) =>
- (!query.code || qc.code.toLowerCase().includes(query.code.toLowerCase())) &&
- (!query.name || qc.name.toLowerCase().includes(query.name.toLowerCase()))
- )
- );
- }}
- onReset={onReset}
- />
- <SearchResults<QcCategoryResult>
- items={filteredQcCategories}
- columns={columns}
- />
-
- {/* View Mappings Dialog */}
- <Dialog open={openDialog} onClose={() => setOpenDialog(false)} maxWidth="md" fullWidth>
- <DialogTitle>
- {t("Association Details")} - {selectedCategory?.name}
- </DialogTitle>
- <DialogContent>
- <Stack spacing={2} sx={{ mt: 1 }}>
- <Box sx={{ display: "flex", justifyContent: "flex-end" }}>
- <Button
- variant="contained"
- startIcon={<Add />}
- onClick={handleAddMapping}
- >
- {t("Add Association")}
- </Button>
- </Box>
- <TableContainer>
- <Table>
- <TableHead>
- <TableRow>
- <TableCell>{t("Order")}</TableCell>
- <TableCell>{t("Qc Item Code")}</TableCell>
- <TableCell>{t("Qc Item Name")}</TableCell>
- <TableCell>{t("Description")}</TableCell>
- <TableCell>{t("Actions")}</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {mappings.length === 0 ? (
- <TableRow>
- <TableCell colSpan={5} align="center">
- {t("No associations found")}
- </TableCell>
- </TableRow>
- ) : (
- mappings.map((mapping) => (
- <TableRow key={mapping.id}>
- <TableCell>{mapping.order}</TableCell>
- <TableCell>{mapping.code}</TableCell>
- <TableCell>{mapping.name}</TableCell>
- <TableCell>{mapping.description || "-"}</TableCell>
- <TableCell>
- <IconButton
- color="error"
- size="small"
- onClick={() => handleDeleteMapping(mapping.id)}
- >
- <Delete />
- </IconButton>
- </TableCell>
- </TableRow>
- ))
- )}
- </TableBody>
- </Table>
- </TableContainer>
- </Stack>
- </DialogContent>
- <DialogActions>
- <Button onClick={() => setOpenDialog(false)}>{t("Cancel")}</Button>
- </DialogActions>
- </Dialog>
-
- {/* Add Mapping Dialog */}
- <Dialog open={openAddDialog} onClose={() => setOpenAddDialog(false)} maxWidth="sm" fullWidth>
- <DialogTitle>{t("Add Association")}</DialogTitle>
- <DialogContent>
- <Stack spacing={2} sx={{ mt: 2 }}>
- <Autocomplete
- options={qcItems}
- getOptionLabel={(option) => `${option.code} - ${option.name}`}
- value={selectedQcItem}
- onChange={(_, newValue) => setSelectedQcItem(newValue)}
- renderInput={(params) => (
- <TextField {...params} label={t("Select Qc Item")} />
- )}
- />
- <TextField
- type="number"
- label={t("Order")}
- value={order}
- onChange={(e) => setOrder(parseInt(e.target.value) || 0)}
- fullWidth
- />
- </Stack>
- </DialogContent>
- <DialogActions>
- <Button onClick={() => setOpenAddDialog(false)}>{t("Cancel")}</Button>
- <Button
- variant="contained"
- onClick={handleSaveMapping}
- disabled={!selectedQcItem}
- >
- {t("Save")}
- </Button>
- </DialogActions>
- </Dialog>
- </Box>
- );
- };
-
- export default Tab1QcCategoryQcItemMapping;
|