Browse Source

update tasks (can edit now), staff, subsidiary, customer, user, rename customer,

tags/Baseline_30082024_FRONTEND_UAT
cyril.tsui 1 year ago
parent
commit
6fdbe94610
25 changed files with 291 additions and 96 deletions
  1. +2
    -2
      src/app/(main)/settings/customer/create/page.tsx
  2. +2
    -2
      src/app/(main)/settings/customer/edit/page.tsx
  3. +4
    -1
      src/app/(main)/tasks/create/page.tsx
  4. +26
    -0
      src/app/(main)/tasks/edit/page.tsx
  5. +8
    -5
      src/app/(main)/tasks/page.tsx
  6. +28
    -2
      src/app/api/tasks/actions.ts
  7. +122
    -69
      src/components/CreateTaskTemplate/CreateTaskTemplate.tsx
  8. +0
    -1
      src/components/CustomerDetail/index.ts
  9. +0
    -0
      src/components/CustomerSave/ContactInfo.tsx
  10. +0
    -0
      src/components/CustomerSave/CustomerInfo.tsx
  11. +2
    -2
      src/components/CustomerSave/CustomerSave.tsx
  12. +4
    -4
      src/components/CustomerSave/CustomerSaveWrapper.tsx
  13. +0
    -0
      src/components/CustomerSave/SubsidiaryAllocation.tsx
  14. +1
    -0
      src/components/CustomerSave/index.ts
  15. +1
    -1
      src/components/StaffSearch/StaffSearch.tsx
  16. +2
    -2
      src/components/SubsidiaryDetail/SubsidiaryDetailWrapper.tsx
  17. +1
    -1
      src/components/SubsidiarySearch/SubsidiarySearch.tsx
  18. +27
    -1
      src/components/TaskTemplateSearch/TaskTemplateSearch.tsx
  19. +1
    -1
      src/components/TeamSearch/TeamSearch.tsx
  20. +1
    -1
      src/components/TransferList/TransferList.tsx
  21. +1
    -1
      src/components/UserSearch/UserSearch.tsx
  22. +2
    -0
      src/i18n/en/common.json
  23. +27
    -0
      src/i18n/en/tasks.json
  24. +2
    -0
      src/i18n/zh/common.json
  25. +27
    -0
      src/i18n/zh/tasks.json

+ 2
- 2
src/app/(main)/settings/customer/create/page.tsx View File

@@ -1,4 +1,4 @@
import CustomerDetail from "@/components/CustomerDetail";
import CustomerSave from "@/components/CustomerSave";
// import { preloadAllTasks } from "@/app/api/tasks"; // import { preloadAllTasks } from "@/app/api/tasks";
import CreateTaskTemplate from "@/components/CreateTaskTemplate"; import CreateTaskTemplate from "@/components/CreateTaskTemplate";
import { I18nProvider, getServerI18n } from "@/i18n"; import { I18nProvider, getServerI18n } from "@/i18n";
@@ -16,7 +16,7 @@ const CreateCustomer: React.FC = async () => {
<> <>
<Typography variant="h4">{t("Create Customer")}</Typography> <Typography variant="h4">{t("Create Customer")}</Typography>
<I18nProvider namespaces={["customer", "common"]}> <I18nProvider namespaces={["customer", "common"]}>
<CustomerDetail />
<CustomerSave />
</I18nProvider> </I18nProvider>
</> </>
); );


+ 2
- 2
src/app/(main)/settings/customer/edit/page.tsx View File

@@ -1,5 +1,5 @@
import { fetchAllSubsidiaries, preloadAllCustomers } from "@/app/api/customer"; import { fetchAllSubsidiaries, preloadAllCustomers } from "@/app/api/customer";
import CustomerDetail from "@/components/CustomerDetail";
import CustomerSave from "@/components/CustomerSave";
// import { preloadAllTasks } from "@/app/api/tasks"; // import { preloadAllTasks } from "@/app/api/tasks";
import CreateTaskTemplate from "@/components/CreateTaskTemplate"; import CreateTaskTemplate from "@/components/CreateTaskTemplate";
import { I18nProvider, getServerI18n } from "@/i18n"; import { I18nProvider, getServerI18n } from "@/i18n";
@@ -18,7 +18,7 @@ const EditCustomer: React.FC = async () => {
<> <>
<Typography variant="h4">{t("Edit Customer")}</Typography> <Typography variant="h4">{t("Edit Customer")}</Typography>
<I18nProvider namespaces={["customer", "common"]}> <I18nProvider namespaces={["customer", "common"]}>
<CustomerDetail />
<CustomerSave />
</I18nProvider> </I18nProvider>
</> </>
); );


+ 4
- 1
src/app/(main)/tasks/create/page.tsx View File

@@ -3,6 +3,7 @@ import CreateTaskTemplate from "@/components/CreateTaskTemplate";
import { getServerI18n } from "@/i18n"; import { getServerI18n } from "@/i18n";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import { Metadata } from "next"; import { Metadata } from "next";
import { I18nProvider } from "@/i18n";


export const metadata: Metadata = { export const metadata: Metadata = {
title: "Create Task Template", title: "Create Task Template",
@@ -15,7 +16,9 @@ const Projects: React.FC = async () => {
return ( return (
<> <>
<Typography variant="h4">{t("Create Task Template")}</Typography> <Typography variant="h4">{t("Create Task Template")}</Typography>
<CreateTaskTemplate />
<I18nProvider namespaces={["tasks", "common"]}>
<CreateTaskTemplate />
</I18nProvider>
</> </>
); );
}; };


+ 26
- 0
src/app/(main)/tasks/edit/page.tsx View File

@@ -0,0 +1,26 @@
import { preloadAllTasks } from "@/app/api/tasks";
import CreateTaskTemplate from "@/components/CreateTaskTemplate";
import { getServerI18n } from "@/i18n";
import Typography from "@mui/material/Typography";
import { Metadata } from "next";
import { I18nProvider } from "@/i18n";

export const metadata: Metadata = {
title: "Edit Task Template",
};

const TaskTemplates: React.FC = async () => {
const { t } = await getServerI18n("tasks");
preloadAllTasks();

return (
<>
<Typography variant="h4">{t("Edit Task Template")}</Typography>
<I18nProvider namespaces={["tasks", "common"]}>
<CreateTaskTemplate />
</I18nProvider>
</>
);
};

export default TaskTemplates;

+ 8
- 5
src/app/(main)/tasks/page.tsx View File

@@ -8,13 +8,14 @@ import Typography from "@mui/material/Typography";
import { Metadata } from "next"; import { Metadata } from "next";
import Link from "next/link"; import Link from "next/link";
import { Suspense } from "react"; import { Suspense } from "react";
import { I18nProvider } from "@/i18n";


export const metadata: Metadata = { export const metadata: Metadata = {
title: "Tasks", title: "Tasks",
}; };


const TaskTemplates: React.FC = async () => { const TaskTemplates: React.FC = async () => {
const { t } = await getServerI18n("projects");
const { t } = await getServerI18n("tasks");
preloadTaskTemplates(); preloadTaskTemplates();


return ( return (
@@ -34,12 +35,14 @@ const TaskTemplates: React.FC = async () => {
LinkComponent={Link} LinkComponent={Link}
href="/tasks/create" href="/tasks/create"
> >
{t("Create Template")}
{t("Create Task Template")}
</Button> </Button>
</Stack> </Stack>
<Suspense fallback={<TaskTemplateSearch.Loading />}>
<TaskTemplateSearch />
</Suspense>
<I18nProvider namespaces={["tasks", "common"]}>
<Suspense fallback={<TaskTemplateSearch.Loading />}>
<TaskTemplateSearch />
</Suspense>
</I18nProvider>
</> </>
); );
}; };


+ 28
- 2
src/app/api/tasks/actions.ts View File

@@ -1,6 +1,6 @@
"use server"; "use server";


import { serverFetchJson } from "@/app/utils/fetchUtil";
import { serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil";
import { BASE_API_URL } from "@/config/api"; import { BASE_API_URL } from "@/config/api";
import { TaskTemplate } from "."; import { TaskTemplate } from ".";
import { revalidateTag } from "next/cache"; import { revalidateTag } from "next/cache";
@@ -9,11 +9,13 @@ export interface NewTaskTemplateFormInputs {
code: string; code: string;
name: string; name: string;
taskIds: number[]; taskIds: number[];

id: number | null;
} }


export const saveTaskTemplate = async (data: NewTaskTemplateFormInputs) => { export const saveTaskTemplate = async (data: NewTaskTemplateFormInputs) => {
const newTaskTemplate = await serverFetchJson<TaskTemplate>( const newTaskTemplate = await serverFetchJson<TaskTemplate>(
`${BASE_API_URL}/tasks/templates/new`,
`${BASE_API_URL}/tasks/templates/save`,
{ {
method: "POST", method: "POST",
body: JSON.stringify(data), body: JSON.stringify(data),
@@ -25,3 +27,27 @@ export const saveTaskTemplate = async (data: NewTaskTemplateFormInputs) => {


return newTaskTemplate; return newTaskTemplate;
}; };

export const fetchTaskTemplate = async (id: number) => {
const taskTemplate = await serverFetchJson<TaskTemplate>(
`${BASE_API_URL}/tasks/templates/${id}`,
{
method: "GET",
headers: { "Content-Type": "application/json" },
},
);

return taskTemplate;
};

export const deleteTaskTemplate = async (id: number) => {
const taskTemplate = await serverFetchWithNoContent(
`${BASE_API_URL}/tasks/templates/${id}`,
{
method: "DELETE",
headers: { "Content-Type": "application/json" },
},
);

return taskTemplate
};

+ 122
- 69
src/components/CreateTaskTemplate/CreateTaskTemplate.tsx View File

@@ -10,15 +10,17 @@ import TransferList from "../TransferList";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import Check from "@mui/icons-material/Check"; import Check from "@mui/icons-material/Check";
import Close from "@mui/icons-material/Close"; import Close from "@mui/icons-material/Close";
import { useRouter } from "next/navigation";
import { useRouter, useSearchParams } from "next/navigation";
import React from "react"; import React from "react";
import Stack from "@mui/material/Stack"; import Stack from "@mui/material/Stack";
import { Task } from "@/app/api/tasks"; import { Task } from "@/app/api/tasks";
import { import {
NewTaskTemplateFormInputs, NewTaskTemplateFormInputs,
fetchTaskTemplate,
saveTaskTemplate, saveTaskTemplate,
} from "@/app/api/tasks/actions"; } from "@/app/api/tasks/actions";
import { SubmitHandler, useForm } from "react-hook-form";
import { SubmitHandler, useFieldArray, useForm } from "react-hook-form";
import { errorDialog, submitDialog, successDialog } from "../Swal/CustomAlerts";


interface Props { interface Props {
tasks: Task[]; tasks: Task[];
@@ -27,6 +29,7 @@ interface Props {
const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => { const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => {
const { t } = useTranslation(); const { t } = useTranslation();


const searchParams = useSearchParams()
const router = useRouter(); const router = useRouter();
const handleCancel = () => { const handleCancel = () => {
router.back(); router.back();
@@ -49,6 +52,7 @@ const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => {
handleSubmit, handleSubmit,
setValue, setValue,
watch, watch,
resetField,
formState: { errors, isSubmitting }, formState: { errors, isSubmitting },
} = useForm<NewTaskTemplateFormInputs>({ defaultValues: { taskIds: [] } }); } = useForm<NewTaskTemplateFormInputs>({ defaultValues: { taskIds: [] } });


@@ -57,12 +61,56 @@ const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => {
return items.filter((item) => currentTaskIds.includes(item.id)); return items.filter((item) => currentTaskIds.includes(item.id));
}, [currentTaskIds, items]); }, [currentTaskIds, items]);


const [refTaskTemplate, setRefTaskTemplate] = React.useState<NewTaskTemplateFormInputs>()
const id = searchParams.get('id')

const fetchCurrentTaskTemplate = async () => {
try {
const taskTemplate = await fetchTaskTemplate(parseInt(id!!))

const defaultValues = {
id: parseInt(id!!),
code: taskTemplate.code ?? null,
name: taskTemplate.name ?? null,
taskIds: taskTemplate.tasks.map(task => task.id) ?? [],
}

setRefTaskTemplate(defaultValues)
} catch (e) {
console.log(e)
}
}

React.useLayoutEffect(() => {
if (id !== null && parseInt(id) > 0) fetchCurrentTaskTemplate()
}, [id])

React.useEffect(() => {
if (refTaskTemplate) {
setValue("taskIds", refTaskTemplate.taskIds)
resetField("code", { defaultValue: refTaskTemplate.code })
resetField("name", { defaultValue: refTaskTemplate.name })
setValue("id", refTaskTemplate.id)
}
}, [refTaskTemplate])

const onSubmit: SubmitHandler<NewTaskTemplateFormInputs> = React.useCallback( const onSubmit: SubmitHandler<NewTaskTemplateFormInputs> = React.useCallback(
async (data) => { async (data) => {
try { try {
setServerError(""); setServerError("");
await saveTaskTemplate(data);
router.replace("/tasks");
submitDialog(async () => {
const response = await saveTaskTemplate(data);

if (response?.id !== null && response?.id !== undefined && response?.id > 0) {
successDialog(t("Submit Success"), t).then(() => {
router.replace("/tasks");
})
} else {
errorDialog(t("Submit Fail"), t).then(() => {
return false
})
}
}, t)
} catch (e) { } catch (e) {
setServerError(t("An error has occurred. Please try again later.")); setServerError(t("An error has occurred. Please try again later."));
} }
@@ -71,72 +119,77 @@ const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => {
); );


return ( return (
<Stack component="form" onSubmit={handleSubmit(onSubmit)} gap={2}>
<Card>
<CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
<Typography variant="overline">{t("Task List Setup")}</Typography>
<Grid
container
spacing={2}
columns={{ xs: 6, sm: 12 }}
marginBlockEnd={1}
>
<Grid item xs={6}>
<TextField
label={t("Task Template Code")}
fullWidth
{...register("code", {
required: t("Task template code is required"),
})}
error={Boolean(errors.code?.message)}
helperText={errors.code?.message}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("Task Template Name")}
fullWidth
{...register("name", {
required: t("Task template name is required"),
})}
error={Boolean(errors.name?.message)}
helperText={errors.name?.message}
<>
{
(id === null || refTaskTemplate !== undefined) && <Stack component="form" onSubmit={handleSubmit(onSubmit)} gap={2}>
<Card>
<CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
<Typography variant="overline">{t("Task List Setup")}</Typography>
<Grid
container
spacing={2}
columns={{ xs: 6, sm: 12 }}
marginBlockEnd={1}
>
<Grid item xs={6}>
<TextField
label={t("Task Template Code")}
fullWidth
{...register("code", {
required: t("Task template code is required"),
})}
error={Boolean(errors.code?.message)}
helperText={errors.code?.message}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("Task Template Name")}
fullWidth
{...register("name", {
required: t("Task template name is required"),
})}
error={Boolean(errors.name?.message)}
helperText={errors.name?.message}
/>
</Grid>
</Grid>
<TransferList
allItems={items}
selectedItems={selectedItems}
onChange={(selectedTasks) => {
setValue(
"taskIds",
selectedTasks.map((item) => item.id),
);
}}
allItemsLabel={t("Task Pool")}
selectedItemsLabel={t("Task List Template")}
/> />
</Grid>
</Grid>
<TransferList
allItems={items}
selectedItems={selectedItems}
onChange={(selectedTasks) => {
setValue(
"taskIds",
selectedTasks.map((item) => item.id),
);
}}
allItemsLabel={t("Task Pool")}
selectedItemsLabel={t("Task List Template")}
/>
</CardContent>
</Card>
{serverError && (
<Typography variant="body2" color="error" alignSelf="flex-end">
{serverError}
</Typography>
)}
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button variant="outlined" startIcon={<Close />} onClick={handleCancel}>
{t("Cancel")}
</Button>
<Button
variant="contained"
startIcon={<Check />}
type="submit"
disabled={isSubmitting}
>
{t("Confirm")}
</Button>
</Stack>
</Stack>
</CardContent>
</Card>
{
serverError && (
<Typography variant="body2" color="error" alignSelf="flex-end">
{serverError}
</Typography>
)
}
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button variant="outlined" startIcon={<Close />} onClick={handleCancel}>
{t("Cancel")}
</Button>
<Button
variant="contained"
startIcon={<Check />}
type="submit"
disabled={isSubmitting}
>
{t("Confirm")}
</Button>
</Stack>
</Stack >}
</>
); );
}; };




+ 0
- 1
src/components/CustomerDetail/index.ts View File

@@ -1 +0,0 @@
export { default } from "./CustomerDetailWrapper";

src/components/CustomerDetail/ContactInfo.tsx → src/components/CustomerSave/ContactInfo.tsx View File


src/components/CustomerDetail/CustomerInfo.tsx → src/components/CustomerSave/CustomerInfo.tsx View File


src/components/CustomerDetail/CustomerDetail.tsx → src/components/CustomerSave/CustomerSave.tsx View File

@@ -42,7 +42,7 @@ const hasErrorsInTab = (
} }
}; };


const CustomerDetail: React.FC<Props> = ({
const CustomerSave: React.FC<Props> = ({
subsidiaries, subsidiaries,
customerTypes, customerTypes,
}) => { }) => {
@@ -277,4 +277,4 @@ const CustomerDetail: React.FC<Props> = ({
); );
}; };


export default CustomerDetail;
export default CustomerSave;

src/components/CustomerDetail/CustomerDetailWrapper.tsx → src/components/CustomerSave/CustomerSaveWrapper.tsx View File

@@ -3,7 +3,7 @@
// import { fetchProjectCategories } from "@/app/api/projects"; // import { fetchProjectCategories } from "@/app/api/projects";
// import { fetchTeamLeads } from "@/app/api/staff"; // import { fetchTeamLeads } from "@/app/api/staff";
import { fetchCustomerTypes, fetchAllSubsidiaries } from "@/app/api/customer"; import { fetchCustomerTypes, fetchAllSubsidiaries } from "@/app/api/customer";
import CustomerDetail from "./CustomerDetail";
import CustomerSave from "./CustomerSave";


// type Props = { // type Props = {
// params: { // params: {
@@ -11,7 +11,7 @@ import CustomerDetail from "./CustomerDetail";
// }; // };
// }; // };


const CustomerDetailWrapper: React.FC = async () => {
const CustomerSaveWrapper: React.FC = async () => {
// const { params } = props // const { params } = props
// console.log(params) // console.log(params)
const [subsidiaries, customerTypes] = const [subsidiaries, customerTypes] =
@@ -21,8 +21,8 @@ const CustomerDetailWrapper: React.FC = async () => {
]); ]);


return ( return (
<CustomerDetail subsidiaries={subsidiaries} customerTypes={customerTypes} />
<CustomerSave subsidiaries={subsidiaries} customerTypes={customerTypes} />
); );
}; };


export default CustomerDetailWrapper;
export default CustomerSaveWrapper;

src/components/CustomerDetail/SubsidiaryAllocation.tsx → src/components/CustomerSave/SubsidiaryAllocation.tsx View File


+ 1
- 0
src/components/CustomerSave/index.ts View File

@@ -0,0 +1 @@
export { default } from "./CustomerSaveWrapper";

+ 1
- 1
src/components/StaffSearch/StaffSearch.tsx View File

@@ -68,7 +68,7 @@ const StaffSearch: React.FC<Props> = ({ staff }) => {
const deleteClick = useCallback((staff: StaffResult) => { const deleteClick = useCallback((staff: StaffResult) => {
deleteDialog(async () => { deleteDialog(async () => {
await deleteStaff(staff.id); await deleteStaff(staff.id);
successDialog("Delete Success", t);
successDialog(t("Delete Success"), t);
setFilteredStaff((prev) => prev.filter((obj) => obj.id !== staff.id)); setFilteredStaff((prev) => prev.filter((obj) => obj.id !== staff.id));
}, t); }, t);
}, []); }, []);


+ 2
- 2
src/components/SubsidiaryDetail/SubsidiaryDetailWrapper.tsx View File

@@ -1,7 +1,7 @@
import { fetchAllCustomers, fetchSubsidiaryTypes } from "@/app/api/subsidiary"; import { fetchAllCustomers, fetchSubsidiaryTypes } from "@/app/api/subsidiary";
import SubsidiaryDetail from "./SubsidiaryDetail"; import SubsidiaryDetail from "./SubsidiaryDetail";


const CustomerDetailWrapper: React.FC = async () => {
const CustomerSaveWrapper: React.FC = async () => {
const [customers, subsidiaryTypes] = const [customers, subsidiaryTypes] =
await Promise.all([ await Promise.all([
fetchAllCustomers(), fetchAllCustomers(),
@@ -13,4 +13,4 @@ const CustomerDetailWrapper: React.FC = async () => {
); );
}; };


export default CustomerDetailWrapper;
export default CustomerSaveWrapper;

+ 1
- 1
src/components/SubsidiarySearch/SubsidiarySearch.tsx View File

@@ -46,7 +46,7 @@ const SubsidiarySearch: React.FC<Props> = ({ subsidiaries }) => {
deleteDialog(async() => { deleteDialog(async() => {
await deleteSubsidiary(subsidiary.id) await deleteSubsidiary(subsidiary.id)


successDialog("Delete Success", t)
successDialog(t("Delete Success"), t)


setFilteredSubsidiaries((prev) => prev.filter((obj) => obj.id !== subsidiary.id)) setFilteredSubsidiaries((prev) => prev.filter((obj) => obj.id !== subsidiary.id))
}, t) }, t)


+ 27
- 1
src/components/TaskTemplateSearch/TaskTemplateSearch.tsx View File

@@ -6,6 +6,10 @@ import SearchBox, { Criterion } from "../SearchBox";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "../SearchResults"; import SearchResults, { Column } from "../SearchResults";
import EditNote from "@mui/icons-material/EditNote"; import EditNote from "@mui/icons-material/EditNote";
import { useRouter, useSearchParams } from "next/navigation";
import DeleteIcon from '@mui/icons-material/Delete';
import { deleteDialog, successDialog } from "../Swal/CustomAlerts";
import { deleteTaskTemplate } from "@/app/api/tasks/actions";


interface Props { interface Props {
taskTemplates: TaskTemplate[]; taskTemplates: TaskTemplate[];
@@ -16,6 +20,8 @@ type SearchParamNames = keyof SearchQuery;


const TaskTemplateSearch: React.FC<Props> = ({ taskTemplates }) => { const TaskTemplateSearch: React.FC<Props> = ({ taskTemplates }) => {
const { t } = useTranslation("tasks"); const { t } = useTranslation("tasks");
const searchParams = useSearchParams()
const router = useRouter()


const [filteredTemplates, setFilteredTemplates] = useState(taskTemplates); const [filteredTemplates, setFilteredTemplates] = useState(taskTemplates);
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
@@ -30,7 +36,20 @@ const TaskTemplateSearch: React.FC<Props> = ({ taskTemplates }) => {
}, [taskTemplates]); }, [taskTemplates]);


const onTaskClick = useCallback((taskTemplate: TaskTemplate) => { const onTaskClick = useCallback((taskTemplate: TaskTemplate) => {
console.log(taskTemplate);
const params = new URLSearchParams(searchParams.toString())
params.set("id", taskTemplate.id.toString())
router.replace(`/tasks/edit?${params.toString()}`);
}, []);

const onDeleteClick = useCallback((taskTemplate: TaskTemplate) => {

deleteDialog(async () => {
await deleteTaskTemplate(taskTemplate.id)

successDialog(t("Delete Success"), t)

setFilteredTemplates((prev) => prev.filter((obj) => obj.id !== taskTemplate.id))
}, t)
}, []); }, []);


const columns = useMemo<Column<TaskTemplate>[]>( const columns = useMemo<Column<TaskTemplate>[]>(
@@ -43,6 +62,13 @@ const TaskTemplateSearch: React.FC<Props> = ({ taskTemplates }) => {
}, },
{ name: "code", label: t("Task Template Code") }, { name: "code", label: t("Task Template Code") },
{ name: "name", label: t("Task Template Name") }, { name: "name", label: t("Task Template Name") },
{
name: "id",
label: t("Delete"),
onClick: onDeleteClick,
buttonIcon: <DeleteIcon />,
color: "error"
},
], ],
[onTaskClick, t], [onTaskClick, t],
); );


+ 1
- 1
src/components/TeamSearch/TeamSearch.tsx View File

@@ -56,7 +56,7 @@ const TeamSearch: React.FC<Props> = ({ team }) => {
deleteDialog(async () => { deleteDialog(async () => {
await deleteTeam(team.id); await deleteTeam(team.id);


successDialog("Delete Success", t);
successDialog(t("Delete Success"), t);


setFilteredTeam((prev) => prev.filter((obj) => obj.id !== team.id)); setFilteredTeam((prev) => prev.filter((obj) => obj.id !== team.id));
}, t); }, t);


+ 1
- 1
src/components/TransferList/TransferList.tsx View File

@@ -109,7 +109,7 @@ const ItemList: React.FC<ItemListProps> = ({
</ListItemIcon> </ListItemIcon>
<Stack> <Stack>
<Typography variant="subtitle2">{label}</Typography> <Typography variant="subtitle2">{label}</Typography>
<Typography variant="caption">{`${checkedItems.length}/${items.length} selected`}</Typography>
<Typography variant="caption">{`${checkedItems.length}/${items.length} ${t("selected")}`}</Typography>
</Stack> </Stack>
</Stack> </Stack>
<Divider /> <Divider />


+ 1
- 1
src/components/UserSearch/UserSearch.tsx View File

@@ -45,7 +45,7 @@ const UserSearch: React.FC<Props> = ({ users }) => {
deleteDialog(async () => { deleteDialog(async () => {
await deleteUser(users.id); await deleteUser(users.id);


successDialog("Delete Success", t);
successDialog(t("Delete Success"), t);


setFilteredUser((prev) => prev.filter((obj) => obj.id !== users.id)); setFilteredUser((prev) => prev.filter((obj) => obj.id !== users.id));
}, t); }, t);


+ 2
- 0
src/i18n/en/common.json View File

@@ -17,6 +17,8 @@
"Do you want to delete?": "Do you want to delete", "Do you want to delete?": "Do you want to delete",
"Delete Success": "Delete Success", "Delete Success": "Delete Success",
"Details": "Details",
"Delete": "Delete",
"Search": "Search", "Search": "Search",
"Search Criteria": "Search Criteria", "Search Criteria": "Search Criteria",
"Cancel": "Cancel", "Cancel": "Cancel",


+ 27
- 0
src/i18n/en/tasks.json View File

@@ -0,0 +1,27 @@
{
"Task Template": "Task Template",
"Create Task Template": "Create Task Template",
"Edit Task Template": "Edit Task Template",

"Task Template Code": "Task Template Code",
"Task Template Name": "Task Template Name",
"Task List Setup": "Task List Setup",
"Task Pool": "Task Pool",
"Task List Template": "Task List Template",

"Task template code is required": "Task template code is required",
"Task template name is required": "Task template name is required",

"Do you want to submit?": "Do you want to submit?",
"Submit Success": "Submit Success",
"Submit Fail": "Submit Fail",
"Do you want to delete?": "Do you want to delete?",
"Delete Success": "Delete Success",

"selected": "selected",
"Details": "Details",
"Delete": "Delete",
"Cancel": "Cancel",
"Submit": "Submit",
"Confirm": "Confirm"
}

+ 2
- 0
src/i18n/zh/common.json View File

@@ -15,6 +15,8 @@
"Do you want to delete?": "你是否確認要刪除?", "Do you want to delete?": "你是否確認要刪除?",
"Delete Success": "刪除成功", "Delete Success": "刪除成功",
"Details": "詳情",
"Delete": "刪除",
"Search": "搜尋", "Search": "搜尋",
"Search Criteria": "搜尋條件", "Search Criteria": "搜尋條件",
"Cancel": "取消", "Cancel": "取消",


+ 27
- 0
src/i18n/zh/tasks.json View File

@@ -0,0 +1,27 @@
{
"Task Template": "工作範本",
"Create Task Template": "建立工作範本",
"Edit Task Template": "編輯工作範本",

"Task Template Code": "工作範本編號",
"Task Template Name": "工作範本名稱",
"Task List Setup": "工作名單設置",
"Task Pool": "所有工作",
"Task List Template": "工作名單範本",

"Task template code is required": "需要工作範本編號",
"Task template name is required": "需要工作範本名稱",

"Do you want to submit?": "你是否確認要提交?",
"Submit Success": "提交成功",
"Submit Fail": "提交失敗",
"Do you want to delete?": "你是否確認要刪除?",
"Delete Success": "刪除成功",

"selected": "已選擇",
"Details": "詳情",
"Delete": "刪除",
"Cancel": "取消",
"Submit": "提交",
"Confirm": "確認"
}

Loading…
Cancel
Save