diff --git a/src/app/(main)/settings/customer/create/page.tsx b/src/app/(main)/settings/customer/create/page.tsx
index e0dc0e0..13b38eb 100644
--- a/src/app/(main)/settings/customer/create/page.tsx
+++ b/src/app/(main)/settings/customer/create/page.tsx
@@ -1,4 +1,4 @@
-import CustomerDetail from "@/components/CustomerDetail";
+import CustomerSave from "@/components/CustomerSave";
// import { preloadAllTasks } from "@/app/api/tasks";
import CreateTaskTemplate from "@/components/CreateTaskTemplate";
import { I18nProvider, getServerI18n } from "@/i18n";
@@ -16,7 +16,7 @@ const CreateCustomer: React.FC = async () => {
<>
{t("Create Customer")}
-
+
>
);
diff --git a/src/app/(main)/settings/customer/edit/page.tsx b/src/app/(main)/settings/customer/edit/page.tsx
index 004781b..7755403 100644
--- a/src/app/(main)/settings/customer/edit/page.tsx
+++ b/src/app/(main)/settings/customer/edit/page.tsx
@@ -1,5 +1,5 @@
import { fetchAllSubsidiaries, preloadAllCustomers } from "@/app/api/customer";
-import CustomerDetail from "@/components/CustomerDetail";
+import CustomerSave from "@/components/CustomerSave";
// import { preloadAllTasks } from "@/app/api/tasks";
import CreateTaskTemplate from "@/components/CreateTaskTemplate";
import { I18nProvider, getServerI18n } from "@/i18n";
@@ -18,7 +18,7 @@ const EditCustomer: React.FC = async () => {
<>
{t("Edit Customer")}
-
+
>
);
diff --git a/src/app/(main)/tasks/create/page.tsx b/src/app/(main)/tasks/create/page.tsx
index 656139f..262f624 100644
--- a/src/app/(main)/tasks/create/page.tsx
+++ b/src/app/(main)/tasks/create/page.tsx
@@ -3,6 +3,7 @@ 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: "Create Task Template",
@@ -15,7 +16,9 @@ const Projects: React.FC = async () => {
return (
<>
{t("Create Task Template")}
-
+
+
+
>
);
};
diff --git a/src/app/(main)/tasks/edit/page.tsx b/src/app/(main)/tasks/edit/page.tsx
new file mode 100644
index 0000000..2b2c02c
--- /dev/null
+++ b/src/app/(main)/tasks/edit/page.tsx
@@ -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 (
+ <>
+ {t("Edit Task Template")}
+
+
+
+ >
+ );
+};
+
+export default TaskTemplates;
diff --git a/src/app/(main)/tasks/page.tsx b/src/app/(main)/tasks/page.tsx
index b9e9bf8..bf06dc2 100644
--- a/src/app/(main)/tasks/page.tsx
+++ b/src/app/(main)/tasks/page.tsx
@@ -8,13 +8,14 @@ import Typography from "@mui/material/Typography";
import { Metadata } from "next";
import Link from "next/link";
import { Suspense } from "react";
+import { I18nProvider } from "@/i18n";
export const metadata: Metadata = {
title: "Tasks",
};
const TaskTemplates: React.FC = async () => {
- const { t } = await getServerI18n("projects");
+ const { t } = await getServerI18n("tasks");
preloadTaskTemplates();
return (
@@ -34,12 +35,14 @@ const TaskTemplates: React.FC = async () => {
LinkComponent={Link}
href="/tasks/create"
>
- {t("Create Template")}
+ {t("Create Task Template")}
- }>
-
-
+
+ }>
+
+
+
>
);
};
diff --git a/src/app/api/tasks/actions.ts b/src/app/api/tasks/actions.ts
index 862cc62..2c043be 100644
--- a/src/app/api/tasks/actions.ts
+++ b/src/app/api/tasks/actions.ts
@@ -1,6 +1,6 @@
"use server";
-import { serverFetchJson } from "@/app/utils/fetchUtil";
+import { serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil";
import { BASE_API_URL } from "@/config/api";
import { TaskTemplate } from ".";
import { revalidateTag } from "next/cache";
@@ -9,11 +9,13 @@ export interface NewTaskTemplateFormInputs {
code: string;
name: string;
taskIds: number[];
+
+ id: number | null;
}
export const saveTaskTemplate = async (data: NewTaskTemplateFormInputs) => {
const newTaskTemplate = await serverFetchJson(
- `${BASE_API_URL}/tasks/templates/new`,
+ `${BASE_API_URL}/tasks/templates/save`,
{
method: "POST",
body: JSON.stringify(data),
@@ -25,3 +27,27 @@ export const saveTaskTemplate = async (data: NewTaskTemplateFormInputs) => {
return newTaskTemplate;
};
+
+export const fetchTaskTemplate = async (id: number) => {
+ const taskTemplate = await serverFetchJson(
+ `${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
+};
diff --git a/src/components/CreateTaskTemplate/CreateTaskTemplate.tsx b/src/components/CreateTaskTemplate/CreateTaskTemplate.tsx
index 066c994..f7d5912 100644
--- a/src/components/CreateTaskTemplate/CreateTaskTemplate.tsx
+++ b/src/components/CreateTaskTemplate/CreateTaskTemplate.tsx
@@ -10,15 +10,17 @@ import TransferList from "../TransferList";
import Button from "@mui/material/Button";
import Check from "@mui/icons-material/Check";
import Close from "@mui/icons-material/Close";
-import { useRouter } from "next/navigation";
+import { useRouter, useSearchParams } from "next/navigation";
import React from "react";
import Stack from "@mui/material/Stack";
import { Task } from "@/app/api/tasks";
import {
NewTaskTemplateFormInputs,
+ fetchTaskTemplate,
saveTaskTemplate,
} 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 {
tasks: Task[];
@@ -27,6 +29,7 @@ interface Props {
const CreateTaskTemplate: React.FC = ({ tasks }) => {
const { t } = useTranslation();
+ const searchParams = useSearchParams()
const router = useRouter();
const handleCancel = () => {
router.back();
@@ -49,6 +52,7 @@ const CreateTaskTemplate: React.FC = ({ tasks }) => {
handleSubmit,
setValue,
watch,
+ resetField,
formState: { errors, isSubmitting },
} = useForm({ defaultValues: { taskIds: [] } });
@@ -57,12 +61,56 @@ const CreateTaskTemplate: React.FC = ({ tasks }) => {
return items.filter((item) => currentTaskIds.includes(item.id));
}, [currentTaskIds, items]);
+ const [refTaskTemplate, setRefTaskTemplate] = React.useState()
+ 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 = React.useCallback(
async (data) => {
try {
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) {
setServerError(t("An error has occurred. Please try again later."));
}
@@ -71,72 +119,77 @@ const CreateTaskTemplate: React.FC = ({ tasks }) => {
);
return (
-
-
-
- {t("Task List Setup")}
-
-
-
-
-
-
+ {
+ (id === null || refTaskTemplate !== undefined) &&
+
+
+ {t("Task List Setup")}
+
+
+
+
+
+
+
+
+ {
+ setValue(
+ "taskIds",
+ selectedTasks.map((item) => item.id),
+ );
+ }}
+ allItemsLabel={t("Task Pool")}
+ selectedItemsLabel={t("Task List Template")}
/>
-
-
- {
- setValue(
- "taskIds",
- selectedTasks.map((item) => item.id),
- );
- }}
- allItemsLabel={t("Task Pool")}
- selectedItemsLabel={t("Task List Template")}
- />
-
-
- {serverError && (
-
- {serverError}
-
- )}
-
- } onClick={handleCancel}>
- {t("Cancel")}
-
- }
- type="submit"
- disabled={isSubmitting}
- >
- {t("Confirm")}
-
-
-
+
+
+ {
+ serverError && (
+
+ {serverError}
+
+ )
+ }
+
+ } onClick={handleCancel}>
+ {t("Cancel")}
+
+ }
+ type="submit"
+ disabled={isSubmitting}
+ >
+ {t("Confirm")}
+
+
+ }
+ >
);
};
diff --git a/src/components/CustomerDetail/index.ts b/src/components/CustomerDetail/index.ts
deleted file mode 100644
index a8811e6..0000000
--- a/src/components/CustomerDetail/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./CustomerDetailWrapper";
\ No newline at end of file
diff --git a/src/components/CustomerDetail/ContactInfo.tsx b/src/components/CustomerSave/ContactInfo.tsx
similarity index 100%
rename from src/components/CustomerDetail/ContactInfo.tsx
rename to src/components/CustomerSave/ContactInfo.tsx
diff --git a/src/components/CustomerDetail/CustomerInfo.tsx b/src/components/CustomerSave/CustomerInfo.tsx
similarity index 100%
rename from src/components/CustomerDetail/CustomerInfo.tsx
rename to src/components/CustomerSave/CustomerInfo.tsx
diff --git a/src/components/CustomerDetail/CustomerDetail.tsx b/src/components/CustomerSave/CustomerSave.tsx
similarity index 99%
rename from src/components/CustomerDetail/CustomerDetail.tsx
rename to src/components/CustomerSave/CustomerSave.tsx
index 88a99ad..fc2469e 100644
--- a/src/components/CustomerDetail/CustomerDetail.tsx
+++ b/src/components/CustomerSave/CustomerSave.tsx
@@ -42,7 +42,7 @@ const hasErrorsInTab = (
}
};
-const CustomerDetail: React.FC = ({
+const CustomerSave: React.FC = ({
subsidiaries,
customerTypes,
}) => {
@@ -277,4 +277,4 @@ const CustomerDetail: React.FC = ({
);
};
-export default CustomerDetail;
\ No newline at end of file
+export default CustomerSave;
\ No newline at end of file
diff --git a/src/components/CustomerDetail/CustomerDetailWrapper.tsx b/src/components/CustomerSave/CustomerSaveWrapper.tsx
similarity index 73%
rename from src/components/CustomerDetail/CustomerDetailWrapper.tsx
rename to src/components/CustomerSave/CustomerSaveWrapper.tsx
index 0206940..078f50a 100644
--- a/src/components/CustomerDetail/CustomerDetailWrapper.tsx
+++ b/src/components/CustomerSave/CustomerSaveWrapper.tsx
@@ -3,7 +3,7 @@
// import { fetchProjectCategories } from "@/app/api/projects";
// import { fetchTeamLeads } from "@/app/api/staff";
import { fetchCustomerTypes, fetchAllSubsidiaries } from "@/app/api/customer";
-import CustomerDetail from "./CustomerDetail";
+import CustomerSave from "./CustomerSave";
// type Props = {
// params: {
@@ -11,7 +11,7 @@ import CustomerDetail from "./CustomerDetail";
// };
// };
-const CustomerDetailWrapper: React.FC = async () => {
+const CustomerSaveWrapper: React.FC = async () => {
// const { params } = props
// console.log(params)
const [subsidiaries, customerTypes] =
@@ -21,8 +21,8 @@ const CustomerDetailWrapper: React.FC = async () => {
]);
return (
-
+
);
};
-export default CustomerDetailWrapper;
+export default CustomerSaveWrapper;
diff --git a/src/components/CustomerDetail/SubsidiaryAllocation.tsx b/src/components/CustomerSave/SubsidiaryAllocation.tsx
similarity index 100%
rename from src/components/CustomerDetail/SubsidiaryAllocation.tsx
rename to src/components/CustomerSave/SubsidiaryAllocation.tsx
diff --git a/src/components/CustomerSave/index.ts b/src/components/CustomerSave/index.ts
new file mode 100644
index 0000000..ea74d25
--- /dev/null
+++ b/src/components/CustomerSave/index.ts
@@ -0,0 +1 @@
+export { default } from "./CustomerSaveWrapper";
\ No newline at end of file
diff --git a/src/components/StaffSearch/StaffSearch.tsx b/src/components/StaffSearch/StaffSearch.tsx
index fc6204d..4111d14 100644
--- a/src/components/StaffSearch/StaffSearch.tsx
+++ b/src/components/StaffSearch/StaffSearch.tsx
@@ -68,7 +68,7 @@ const StaffSearch: React.FC = ({ staff }) => {
const deleteClick = useCallback((staff: StaffResult) => {
deleteDialog(async () => {
await deleteStaff(staff.id);
- successDialog("Delete Success", t);
+ successDialog(t("Delete Success"), t);
setFilteredStaff((prev) => prev.filter((obj) => obj.id !== staff.id));
}, t);
}, []);
diff --git a/src/components/SubsidiaryDetail/SubsidiaryDetailWrapper.tsx b/src/components/SubsidiaryDetail/SubsidiaryDetailWrapper.tsx
index 1a9ced0..c335042 100644
--- a/src/components/SubsidiaryDetail/SubsidiaryDetailWrapper.tsx
+++ b/src/components/SubsidiaryDetail/SubsidiaryDetailWrapper.tsx
@@ -1,7 +1,7 @@
import { fetchAllCustomers, fetchSubsidiaryTypes } from "@/app/api/subsidiary";
import SubsidiaryDetail from "./SubsidiaryDetail";
-const CustomerDetailWrapper: React.FC = async () => {
+const CustomerSaveWrapper: React.FC = async () => {
const [customers, subsidiaryTypes] =
await Promise.all([
fetchAllCustomers(),
@@ -13,4 +13,4 @@ const CustomerDetailWrapper: React.FC = async () => {
);
};
-export default CustomerDetailWrapper;
+export default CustomerSaveWrapper;
diff --git a/src/components/SubsidiarySearch/SubsidiarySearch.tsx b/src/components/SubsidiarySearch/SubsidiarySearch.tsx
index 95c901f..c4e1db5 100644
--- a/src/components/SubsidiarySearch/SubsidiarySearch.tsx
+++ b/src/components/SubsidiarySearch/SubsidiarySearch.tsx
@@ -46,7 +46,7 @@ const SubsidiarySearch: React.FC = ({ subsidiaries }) => {
deleteDialog(async() => {
await deleteSubsidiary(subsidiary.id)
- successDialog("Delete Success", t)
+ successDialog(t("Delete Success"), t)
setFilteredSubsidiaries((prev) => prev.filter((obj) => obj.id !== subsidiary.id))
}, t)
diff --git a/src/components/TaskTemplateSearch/TaskTemplateSearch.tsx b/src/components/TaskTemplateSearch/TaskTemplateSearch.tsx
index 72be3c1..7563f53 100644
--- a/src/components/TaskTemplateSearch/TaskTemplateSearch.tsx
+++ b/src/components/TaskTemplateSearch/TaskTemplateSearch.tsx
@@ -6,6 +6,10 @@ import SearchBox, { Criterion } from "../SearchBox";
import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "../SearchResults";
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 {
taskTemplates: TaskTemplate[];
@@ -16,6 +20,8 @@ type SearchParamNames = keyof SearchQuery;
const TaskTemplateSearch: React.FC = ({ taskTemplates }) => {
const { t } = useTranslation("tasks");
+ const searchParams = useSearchParams()
+ const router = useRouter()
const [filteredTemplates, setFilteredTemplates] = useState(taskTemplates);
const searchCriteria: Criterion[] = useMemo(
@@ -30,7 +36,20 @@ const TaskTemplateSearch: React.FC = ({ taskTemplates }) => {
}, [taskTemplates]);
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[]>(
@@ -43,6 +62,13 @@ const TaskTemplateSearch: React.FC = ({ taskTemplates }) => {
},
{ name: "code", label: t("Task Template Code") },
{ name: "name", label: t("Task Template Name") },
+ {
+ name: "id",
+ label: t("Delete"),
+ onClick: onDeleteClick,
+ buttonIcon: ,
+ color: "error"
+ },
],
[onTaskClick, t],
);
diff --git a/src/components/TeamSearch/TeamSearch.tsx b/src/components/TeamSearch/TeamSearch.tsx
index a1db872..71ecb79 100644
--- a/src/components/TeamSearch/TeamSearch.tsx
+++ b/src/components/TeamSearch/TeamSearch.tsx
@@ -56,7 +56,7 @@ const TeamSearch: React.FC = ({ team }) => {
deleteDialog(async () => {
await deleteTeam(team.id);
- successDialog("Delete Success", t);
+ successDialog(t("Delete Success"), t);
setFilteredTeam((prev) => prev.filter((obj) => obj.id !== team.id));
}, t);
diff --git a/src/components/TransferList/TransferList.tsx b/src/components/TransferList/TransferList.tsx
index 84cd468..232c486 100644
--- a/src/components/TransferList/TransferList.tsx
+++ b/src/components/TransferList/TransferList.tsx
@@ -109,7 +109,7 @@ const ItemList: React.FC = ({
{label}
- {`${checkedItems.length}/${items.length} selected`}
+ {`${checkedItems.length}/${items.length} ${t("selected")}`}
diff --git a/src/components/UserSearch/UserSearch.tsx b/src/components/UserSearch/UserSearch.tsx
index 095c544..658d25c 100644
--- a/src/components/UserSearch/UserSearch.tsx
+++ b/src/components/UserSearch/UserSearch.tsx
@@ -45,7 +45,7 @@ const UserSearch: React.FC = ({ users }) => {
deleteDialog(async () => {
await deleteUser(users.id);
- successDialog("Delete Success", t);
+ successDialog(t("Delete Success"), t);
setFilteredUser((prev) => prev.filter((obj) => obj.id !== users.id));
}, t);
diff --git a/src/i18n/en/common.json b/src/i18n/en/common.json
index 5f1d289..a7d019a 100644
--- a/src/i18n/en/common.json
+++ b/src/i18n/en/common.json
@@ -17,6 +17,8 @@
"Do you want to delete?": "Do you want to delete",
"Delete Success": "Delete Success",
+ "Details": "Details",
+ "Delete": "Delete",
"Search": "Search",
"Search Criteria": "Search Criteria",
"Cancel": "Cancel",
diff --git a/src/i18n/en/tasks.json b/src/i18n/en/tasks.json
new file mode 100644
index 0000000..d70d00a
--- /dev/null
+++ b/src/i18n/en/tasks.json
@@ -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"
+}
\ No newline at end of file
diff --git a/src/i18n/zh/common.json b/src/i18n/zh/common.json
index e4642ea..4ff2fcf 100644
--- a/src/i18n/zh/common.json
+++ b/src/i18n/zh/common.json
@@ -15,6 +15,8 @@
"Do you want to delete?": "你是否確認要刪除?",
"Delete Success": "刪除成功",
+ "Details": "詳情",
+ "Delete": "刪除",
"Search": "搜尋",
"Search Criteria": "搜尋條件",
"Cancel": "取消",
diff --git a/src/i18n/zh/tasks.json b/src/i18n/zh/tasks.json
new file mode 100644
index 0000000..16ba727
--- /dev/null
+++ b/src/i18n/zh/tasks.json
@@ -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": "確認"
+}
\ No newline at end of file