| @@ -2,10 +2,11 @@ | |||||
| import { serverFetchJson, serverFetchWithNoContent } 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 { MailSetting } from "."; | |||||
| import { MailSetting, MailTemplate } from "."; | |||||
| export interface MailSave { | export interface MailSave { | ||||
| settings: MailSetting[]; | settings: MailSetting[]; | ||||
| templates: MailTemplate[]; | |||||
| // template: MailTemplate; | // template: MailTemplate; | ||||
| } | } | ||||
| @@ -1,6 +1,7 @@ | |||||
| import { serverFetchJson } from "@/app/utils/fetchUtil"; | import { serverFetchJson } from "@/app/utils/fetchUtil"; | ||||
| import { BASE_API_URL } from "@/config/api"; | import { BASE_API_URL } from "@/config/api"; | ||||
| import { cache } from "react"; | import { cache } from "react"; | ||||
| import "server-only"; | |||||
| export interface MailSMTP { | export interface MailSMTP { | ||||
| host: string; | host: string; | ||||
| @@ -17,6 +18,20 @@ export interface MailSetting { | |||||
| type: string; | type: string; | ||||
| } | } | ||||
| export interface MailTemplate { | |||||
| id: number; | |||||
| to: string; | |||||
| cc: string; | |||||
| code: string; | |||||
| description: string; | |||||
| type: string; | |||||
| params: string; | |||||
| subjectCht: string; | |||||
| subjectEng: string; | |||||
| contentCht: string; | |||||
| contentEng: string; | |||||
| } | |||||
| // export interface MailTemplate { | // export interface MailTemplate { | ||||
| // cc?: string; | // cc?: string; | ||||
| // bcc?: string; | // bcc?: string; | ||||
| @@ -26,6 +41,7 @@ export interface MailSetting { | |||||
| export const preloadMails = () => { | export const preloadMails = () => { | ||||
| fetchMailSetting(); | fetchMailSetting(); | ||||
| fetchMailTemplates(); | |||||
| // fetchMailTimesheetTemplate(); | // fetchMailTimesheetTemplate(); | ||||
| }; | }; | ||||
| @@ -35,6 +51,12 @@ export const fetchMailSetting = cache(async () => { | |||||
| }); | }); | ||||
| }); | }); | ||||
| export const fetchMailTemplates = cache(async () => { | |||||
| return serverFetchJson<MailTemplate[]>(`${BASE_API_URL}/mailTemplates`, { | |||||
| next: { tags: ["mailTemplates"] }, | |||||
| }); | |||||
| }); | |||||
| // export const fetchMailTimesheetTemplate = cache(async () => { | // export const fetchMailTimesheetTemplate = cache(async () => { | ||||
| // return serverFetchJson<MailSetting[]>(`${BASE_API_URL}/mails/timesheet-template`, { | // return serverFetchJson<MailSetting[]>(`${BASE_API_URL}/mails/timesheet-template`, { | ||||
| // next: { tags: ["mailTimesheetTemplate"] }, | // next: { tags: ["mailTimesheetTemplate"] }, | ||||
| @@ -21,7 +21,7 @@ | |||||
| overflow: hidden; | overflow: hidden; | ||||
| /* palette.neutral[200] */ | /* palette.neutral[200] */ | ||||
| transition: border-color 0.3s, box-shadow 0.3s; | transition: border-color 0.3s, box-shadow 0.3s; | ||||
| border-color: #F04438; | border-color: #F04438; | ||||
| /* palette.primary.main */ | /* palette.primary.main */ | ||||
| box-shadow: #F04438 0 0 0 2px; | box-shadow: #F04438 0 0 0 2px; | ||||
| @@ -41,7 +41,7 @@ | |||||
| display: none; | display: none; | ||||
| } | } | ||||
| :not(.tiptap-error) > .tiptap:focus { | |||||
| :not(.tiptap-error)>.tiptap:focus { | |||||
| background-color: transparent; | background-color: transparent; | ||||
| border-color: #8dba00; | border-color: #8dba00; | ||||
| /* palette.primary.main */ | /* palette.primary.main */ | ||||
| @@ -53,6 +53,74 @@ | |||||
| outline: none; | outline: none; | ||||
| } | } | ||||
| /* Basic editor styles */ | |||||
| .tiptap { | |||||
| :first-child { | |||||
| margin-top: 0; | |||||
| } | |||||
| /* Table-specific styling */ | |||||
| table { | |||||
| border-collapse: collapse; | |||||
| margin: 0; | |||||
| overflow: hidden; | |||||
| table-layout: fixed; | |||||
| width: 100%; | |||||
| td, | |||||
| th { | |||||
| border: 1px solid #000000; | |||||
| box-sizing: border-box; | |||||
| min-width: 1em; | |||||
| padding: 6px 8px; | |||||
| position: relative; | |||||
| vertical-align: top; | |||||
| >* { | |||||
| margin-bottom: 0; | |||||
| } | |||||
| } | |||||
| th { | |||||
| background-color: #939393; | |||||
| font-weight: bold; | |||||
| text-align: left; | |||||
| } | |||||
| .selectedCell:after { | |||||
| background: rgba(180, 180, 180, 0.467); | |||||
| content: ""; | |||||
| left: 0; | |||||
| right: 0; | |||||
| top: 0; | |||||
| bottom: 0; | |||||
| pointer-events: none; | |||||
| position: absolute; | |||||
| z-index: 2; | |||||
| } | |||||
| .column-resize-handle { | |||||
| background-color: #d000ff; | |||||
| bottom: -2px; | |||||
| pointer-events: none; | |||||
| position: absolute; | |||||
| right: -2px; | |||||
| top: 0; | |||||
| width: 4px; | |||||
| } | |||||
| } | |||||
| .tableWrapper { | |||||
| margin: 1.5rem 0; | |||||
| overflow-x: auto; | |||||
| } | |||||
| &.resize-cursor { | |||||
| cursor: ew-resize; | |||||
| cursor: col-resize; | |||||
| } | |||||
| } | |||||
| /* Input styles */ | /* Input styles */ | ||||
| /* .tiptap-input { | /* .tiptap-input { | ||||
| font-size: 14px; | font-size: 14px; | ||||
| @@ -14,6 +14,11 @@ import { Color } from '@tiptap/extension-color' | |||||
| import ListItem from "@tiptap/extension-list-item"; | import ListItem from "@tiptap/extension-list-item"; | ||||
| import TextStyle from "@tiptap/extension-text-style"; | import TextStyle from "@tiptap/extension-text-style"; | ||||
| import TextAlign from '@tiptap/extension-text-align' | import TextAlign from '@tiptap/extension-text-align' | ||||
| import Table from '@tiptap/extension-table' | |||||
| import TableCell from '@tiptap/extension-table-cell' | |||||
| import TableHeader from '@tiptap/extension-table-header' | |||||
| import TableRow from '@tiptap/extension-table-row' | |||||
| import Gapcursor from '@tiptap/extension-gapcursor' | |||||
| interface Props { | interface Props { | ||||
| content?: string, | content?: string, | ||||
| @@ -64,7 +69,14 @@ const MailField: React.FC<Props> = ({ | |||||
| Highlight.configure({ multicolor: true }), | Highlight.configure({ multicolor: true }), | ||||
| Color, | Color, | ||||
| ListItem, | ListItem, | ||||
| TabHandler | |||||
| TabHandler, | |||||
| Gapcursor, | |||||
| Table.configure({ | |||||
| resizable: true, | |||||
| }), | |||||
| TableRow, | |||||
| TableHeader, | |||||
| TableCell, | |||||
| ], | ], | ||||
| content: content, | content: content, | ||||
| onUpdate({ editor }) { | onUpdate({ editor }) { | ||||
| @@ -73,15 +85,15 @@ const MailField: React.FC<Props> = ({ | |||||
| } | } | ||||
| console.log(editor.getHTML()) | console.log(editor.getHTML()) | ||||
| }, | }, | ||||
| }) | |||||
| }, []) | |||||
| return ( | return ( | ||||
| <Grid container rowSpacing={1}> | <Grid container rowSpacing={1}> | ||||
| <Grid item xs={12}> | |||||
| <MailToolbar editor={editor} /> | |||||
| </Grid> | |||||
| {/* <Grid item xs={12}> | |||||
| {editor && <MailToolbar editor={editor} />} | |||||
| </Grid> */} | |||||
| <Grid item xs={12} > | <Grid item xs={12} > | ||||
| <EditorContent className={error === true ? "tiptap-error" : ""} label="Template" editor={editor}/> | |||||
| <EditorContent className={error === true ? "tiptap-error" : ""} label="Template" editor={editor} /> | |||||
| </Grid> | </Grid> | ||||
| </Grid> | </Grid> | ||||
| ); | ); | ||||
| @@ -13,6 +13,8 @@ import FormatColorTextIcon from '@mui/icons-material/FormatColorText'; | |||||
| import FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft'; | import FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft'; | ||||
| import FormatAlignJustifyIcon from '@mui/icons-material/FormatAlignJustify'; | import FormatAlignJustifyIcon from '@mui/icons-material/FormatAlignJustify'; | ||||
| import FormatAlignRightIcon from '@mui/icons-material/FormatAlignRight'; | import FormatAlignRightIcon from '@mui/icons-material/FormatAlignRight'; | ||||
| import { useTranslation } from "react-i18next"; | |||||
| import GridOnIcon from '@mui/icons-material/GridOn'; | |||||
| interface Props { | interface Props { | ||||
| editor: Editor | null; | editor: Editor | null; | ||||
| @@ -58,7 +60,7 @@ const fontFamily = [ | |||||
| value: 'Georgia', | value: 'Georgia', | ||||
| }, | }, | ||||
| { | { | ||||
| } | } | ||||
| ] | ] | ||||
| @@ -66,11 +68,12 @@ const MailToolbar: React.FC<Props> = ({ | |||||
| editor | editor | ||||
| }) => { | }) => { | ||||
| const { t } = useTranslation() | |||||
| if (editor == null) { | if (editor == null) { | ||||
| return null | return null | ||||
| } | } | ||||
| const [fontStyle, setFontStyle] = React.useState<string[]>(() => ["alignLeft"]); | |||||
| const [fontStyle, setFontStyle] = React.useState<string[]>(["alignLeft"]); | |||||
| const [colorHighlightValue, setColorHighlightValue] = React.useState<MuiColorInputValue>("red"); | const [colorHighlightValue, setColorHighlightValue] = React.useState<MuiColorInputValue>("red"); | ||||
| const [colorTextValue, setColorTextValue] = React.useState<MuiColorInputValue>("black"); | const [colorTextValue, setColorTextValue] = React.useState<MuiColorInputValue>("black"); | ||||
| const colorHighlightValueInputRef = React.useRef<any>(null); | const colorHighlightValueInputRef = React.useRef<any>(null); | ||||
| @@ -189,6 +192,10 @@ const MailToolbar: React.FC<Props> = ({ | |||||
| } | } | ||||
| }, []) | }, []) | ||||
| const handleInsertTable = useCallback(() => { | |||||
| editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run() | |||||
| }, []) | |||||
| React.useEffect(() => { | React.useEffect(() => { | ||||
| editor.on('selectionUpdate', ({ editor }) => { | editor.on('selectionUpdate', ({ editor }) => { | ||||
| const currentFormatList: string[] = [] | const currentFormatList: string[] = [] | ||||
| @@ -312,6 +319,47 @@ const MailToolbar: React.FC<Props> = ({ | |||||
| <FormatAlignRightIcon /> | <FormatAlignRightIcon /> | ||||
| </ToggleButton> | </ToggleButton> | ||||
| </ToggleButtonGroup> | </ToggleButtonGroup> | ||||
| <ToggleButtonGroup | |||||
| sx={{ marginTop: 2 }} | |||||
| > | |||||
| <ToggleButton id="insertTable" value="insertTable" onClick={() => editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()}> | |||||
| <GridOnIcon />{t("Insert Table")} | |||||
| </ToggleButton> | |||||
| <ToggleButton id="deleteTable" value="deleteTable" onClick={() => editor.chain().focus().deleteTable().run()}>{t("Delete table")}</ToggleButton> | |||||
| <ToggleButton id="addColumnBefore" value="addColumnBefore" onClick={() => editor.chain().focus().addColumnBefore().run()}> | |||||
| {t("Add column before")} | |||||
| </ToggleButton> | |||||
| <ToggleButton id="addColumnAfter" value="addColumnAfter" onClick={() => editor.chain().focus().addColumnAfter().run()}>{t("Add column after")}</ToggleButton> | |||||
| <ToggleButton id="deleteColumn" value="deleteColumn" onClick={() => editor.chain().focus().deleteColumn().run()}>{t("Delete column")}</ToggleButton> | |||||
| <ToggleButton id="addRowBefore" value="addRowBefore" onClick={() => editor.chain().focus().addRowBefore().run()}>{t("Add row before")}</ToggleButton> | |||||
| <ToggleButton id="addRowAfter" value="addRowAfter" onClick={() => editor.chain().focus().addRowAfter().run()}>{t("Add row after")}</ToggleButton> | |||||
| <ToggleButton id="deleteRow" value="deleteRow" onClick={() => editor.chain().focus().deleteRow().run()}>{t("Delete row")}</ToggleButton> | |||||
| <ToggleButton id="mergeCells" value="mergeCells" onClick={() => editor.chain().focus().mergeCells().run()}>{t("Merge cells")}</ToggleButton> | |||||
| <ToggleButton id="splitCell" value="splitCell" onClick={() => editor.chain().focus().splitCell().run()}>{t("Split cell")}</ToggleButton> | |||||
| </ToggleButtonGroup> | |||||
| <ToggleButtonGroup | |||||
| // sx={{ marginLeft: 2 }} | |||||
| > | |||||
| <ToggleButton id="toggleHeaderColumn" value="toggleHeaderColumn" onClick={() => editor.chain().focus().toggleHeaderColumn().run()}> | |||||
| {t("Toggle header column")} | |||||
| </ToggleButton> | |||||
| <ToggleButton id="toggleHeaderRow" value="toggleHeaderRow" onClick={() => editor.chain().focus().toggleHeaderRow().run()}> | |||||
| {t("Toggle header row")} | |||||
| </ToggleButton> | |||||
| <ToggleButton id="toggleHeaderCell" value="toggleHeaderCell" onClick={() => editor.chain().focus().toggleHeaderCell().run()}> | |||||
| {t("Toggle header cell")} | |||||
| </ToggleButton> | |||||
| <ToggleButton id="mergeOrSplit" value="mergeOrSplit" onClick={() => editor.chain().focus().mergeOrSplit().run()}>{t("Merge or split")}</ToggleButton> | |||||
| <ToggleButton id="setCellAttribute" value="setCellAttribute" onClick={() => editor.chain().focus().setCellAttribute('colspan', 2).run()}> | |||||
| {t("Set cell attribute")} | |||||
| </ToggleButton> | |||||
| <ToggleButton id="fixTables" value="fixTables" onClick={() => editor.chain().focus().fixTables().run()}>{t("Fix tables")}</ToggleButton> | |||||
| <ToggleButton id="goToNextCell" value="goToNextCell" onClick={() => editor.chain().focus().goToNextCell().run()}>{t("Go to next cell")}</ToggleButton> | |||||
| <ToggleButton id="goToPreviousCell" value="goToPreviousCell" onClick={() => editor.chain().focus().goToPreviousCell().run()}> | |||||
| {t("Go to previous cell")} | |||||
| </ToggleButton> | |||||
| </ToggleButtonGroup> | |||||
| </Grid> | </Grid> | ||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -5,7 +5,7 @@ import Close from "@mui/icons-material/Close"; | |||||
| import Button from "@mui/material/Button"; | import Button from "@mui/material/Button"; | ||||
| import Stack from "@mui/material/Stack"; | import Stack from "@mui/material/Stack"; | ||||
| import { useRouter } from "next/navigation"; | import { useRouter } from "next/navigation"; | ||||
| import React, { useCallback, useState } from "react"; | |||||
| import React, { useCallback, useContext, useEffect, useState } from "react"; | |||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { | import { | ||||
| FieldErrors, | FieldErrors, | ||||
| @@ -20,6 +20,10 @@ import { Error } from "@mui/icons-material"; | |||||
| import { MailSave, saveMail, testEveryone, test7th, test15th, testSendMail } from "@/app/api/mail/actions"; | import { MailSave, saveMail, testEveryone, test7th, test15th, testSendMail } from "@/app/api/mail/actions"; | ||||
| import SettingDetails from "./SettingDetails"; | import SettingDetails from "./SettingDetails"; | ||||
| import { errorDialog, submitDialog, successDialog } from "../Swal/CustomAlerts"; | import { errorDialog, submitDialog, successDialog } from "../Swal/CustomAlerts"; | ||||
| import { MailTemplate } from "@/app/api/mail"; | |||||
| import TemplateDetails from "./TemplateDetails"; | |||||
| import QrCodeScanner from "../QrCodeScanner/QrCodeScanner"; | |||||
| import { QcCodeScannerContext, useQcCodeScanner } from "../QrCodeScannerProvider/QrCodeScannerProvider"; | |||||
| export interface Props { | export interface Props { | ||||
| defaultInputs?: MailSave, | defaultInputs?: MailSave, | ||||
| @@ -34,10 +38,10 @@ const hasErrorsInTab = ( | |||||
| return ( | return ( | ||||
| errors.settings | errors.settings | ||||
| ); | ); | ||||
| // case 1: | |||||
| // return ( | |||||
| // errors.template | |||||
| // ); | |||||
| case 1: | |||||
| return ( | |||||
| errors.templates | |||||
| ); | |||||
| default: | default: | ||||
| false; | false; | ||||
| } | } | ||||
| @@ -134,6 +138,17 @@ const MailSetting: React.FC<Props> = ({ | |||||
| const errors = formProps.formState.errors; | const errors = formProps.formState.errors; | ||||
| const scanner = useQcCodeScanner() | |||||
| useEffect(() => { | |||||
| scanner.startScan() | |||||
| }, []) | |||||
| console.log("test", scanner.values) | |||||
| if (scanner.values.length > 3) { | |||||
| console.log("test", scanner.values) | |||||
| scanner.resetScan() | |||||
| scanner.stopScan() | |||||
| } | |||||
| return ( | return ( | ||||
| <FormProvider {...formProps}> | <FormProvider {...formProps}> | ||||
| <Stack | <Stack | ||||
| @@ -161,17 +176,18 @@ const MailSetting: React.FC<Props> = ({ | |||||
| } | } | ||||
| iconPosition="end" | iconPosition="end" | ||||
| /> | /> | ||||
| {/* <Tab | |||||
| label={t("Timesheet Template")} | |||||
| <Tab | |||||
| label={t("Template")} | |||||
| icon={ | icon={ | ||||
| hasErrorsInTab(1, errors) ? ( | hasErrorsInTab(1, errors) ? ( | ||||
| <Error sx={{ marginInlineEnd: 1 }} color="error" /> | <Error sx={{ marginInlineEnd: 1 }} color="error" /> | ||||
| ) : undefined | ) : undefined | ||||
| } | } | ||||
| iconPosition="end" | iconPosition="end" | ||||
| /> */} | |||||
| /> | |||||
| </Tabs> | </Tabs> | ||||
| <SettingDetails isActive={tabIndex === 0}/> | <SettingDetails isActive={tabIndex === 0}/> | ||||
| <TemplateDetails isActive={tabIndex === 1} /> | |||||
| {/* <TimesheetMailDetails isActive={tabIndex === 1} /> */} | {/* <TimesheetMailDetails isActive={tabIndex === 1} /> */} | ||||
| <Stack direction="row" justifyContent="flex-end" gap={1}> | <Stack direction="row" justifyContent="flex-end" gap={1}> | ||||
| @@ -1,7 +1,7 @@ | |||||
| // import { fetchUserAbilities } from "@/app/utils/fetchUtil"; | // import { fetchUserAbilities } from "@/app/utils/fetchUtil"; | ||||
| import MailSetting from "./MailSetting"; | import MailSetting from "./MailSetting"; | ||||
| import MailSettingLoading from "./MailSettingLoading"; | import MailSettingLoading from "./MailSettingLoading"; | ||||
| import { fetchMailSetting } from "@/app/api/mail"; | |||||
| import { fetchMailSetting, fetchMailTemplates } from "@/app/api/mail"; | |||||
| interface SubComponents { | interface SubComponents { | ||||
| Loading: typeof MailSettingLoading; | Loading: typeof MailSettingLoading; | ||||
| @@ -11,10 +11,12 @@ const MailSettingWrapper: React.FC & SubComponents = async () => { | |||||
| const [ | const [ | ||||
| // abilities, | // abilities, | ||||
| settings, | settings, | ||||
| templates, | |||||
| // timesheetTemplate, | // timesheetTemplate, | ||||
| ] = await Promise.all([ | ] = await Promise.all([ | ||||
| // fetchUserAbilities(), | // fetchUserAbilities(), | ||||
| fetchMailSetting(), | fetchMailSetting(), | ||||
| fetchMailTemplates(), | |||||
| // fetchMailTimesheetTemplate() | // fetchMailTimesheetTemplate() | ||||
| ]); | ]); | ||||
| @@ -28,6 +30,7 @@ const MailSettingWrapper: React.FC & SubComponents = async () => { | |||||
| <MailSetting | <MailSetting | ||||
| defaultInputs={{ | defaultInputs={{ | ||||
| settings: settings, | settings: settings, | ||||
| templates: templates, | |||||
| // template: tempTimesheetTemplate, | // template: tempTimesheetTemplate, | ||||
| }} | }} | ||||
| /> | /> | ||||
| @@ -55,7 +55,7 @@ const SettingDetails: React.FC<Props> = ({ isActive }) => { | |||||
| fields.map((field, index) => ( | fields.map((field, index) => ( | ||||
| <Grid container key={"row-" + index} justifyContent="flex-start" alignItems="center" spacing={2} columns={{ xs: 6, sm: 12 }} sx={{ mt: 1 }}> | <Grid container key={"row-" + index} justifyContent="flex-start" alignItems="center" spacing={2} columns={{ xs: 6, sm: 12 }} sx={{ mt: 1 }}> | ||||
| <Grid item key={"col-1-" + index} xs={4}> | <Grid item key={"col-1-" + index} xs={4}> | ||||
| <Typography variant="body2">{t(field.name)}</Typography> | |||||
| <Typography variant="body2">{`${t(field.name)}${requiredFields.some(name => field.name.toLowerCase().includes(name)) ? "*" : ""}`}</Typography> | |||||
| </Grid> | </Grid> | ||||
| { | { | ||||
| field.name.toLowerCase().includes("password") === true ? | field.name.toLowerCase().includes("password") === true ? | ||||
| @@ -0,0 +1,239 @@ | |||||
| "use client"; | |||||
| import Stack from "@mui/material/Stack"; | |||||
| import Box from "@mui/material/Box"; | |||||
| import Card from "@mui/material/Card"; | |||||
| import CardContent from "@mui/material/CardContent"; | |||||
| import Grid from "@mui/material/Grid"; | |||||
| import TextField from "@mui/material/TextField"; | |||||
| import Typography from "@mui/material/Typography"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import { Controller, useFieldArray, useFormContext } from "react-hook-form"; | |||||
| import Link from "next/link"; | |||||
| import React, { SyntheticEvent, useCallback, useMemo, useState } from "react"; | |||||
| import MailField from "../MailField/MailField"; | |||||
| import { MailSave } from "@/app/api/mail/actions"; | |||||
| import { MailTemplate } from "@/app/api/mail"; | |||||
| import { isEmpty, keys } from "lodash"; | |||||
| import { Autocomplete, ListSubheader, MenuItem, UseAutocompleteProps } from "@mui/material"; | |||||
| interface Props { | |||||
| isActive: boolean; | |||||
| } | |||||
| interface OptionType { | |||||
| value: number, | |||||
| label: string, | |||||
| group: string, | |||||
| } | |||||
| type fieldKeys = keyof MailTemplate | |||||
| const TemplateDetails: React.FC<Props> = ({ isActive }) => { | |||||
| const { t } = useTranslation(); | |||||
| // const disabledFields: fieldKeys[] = [] | |||||
| // const requiredFields: fieldKeys[] = [] | |||||
| // const skipFields: fieldKeys[] = ["code", "subjectEng", "contentEng"] | |||||
| const [selectedIndex, setSelectedIndex] = useState(0) | |||||
| const { | |||||
| register, | |||||
| formState: { errors }, | |||||
| control, | |||||
| watch, | |||||
| getValues | |||||
| } = useFormContext<MailSave>(); | |||||
| const { | |||||
| fields, | |||||
| } = useFieldArray({ | |||||
| control, | |||||
| name: "templates" | |||||
| }) | |||||
| const options: OptionType[] = useMemo(() => ( | |||||
| fields.map((field, index) => { | |||||
| return { | |||||
| value: index, | |||||
| label: `${field.code} - ${field.description}`, | |||||
| group: field.type | |||||
| } as OptionType | |||||
| }) | |||||
| ), [fields]) | |||||
| const makeAutocompleteChangeHandler = useCallback(() => { | |||||
| return (e: SyntheticEvent, newValue: OptionType) => { | |||||
| setSelectedIndex(() => newValue.value); | |||||
| }; | |||||
| }, []); | |||||
| // const renderFieldsBySwitchCases = useCallback(() => { | |||||
| // const fieldNames = keys(fields[0]) as fieldKeys[]; | |||||
| // return fieldNames | |||||
| // .filter((name) => !skipFields.includes(name)) | |||||
| // .map((name: fieldKeys, index: number) => { | |||||
| // switch (name) { | |||||
| // case "contentCht": | |||||
| // return ( | |||||
| // <Grid item xs={12}> | |||||
| // <Controller | |||||
| // control={control} | |||||
| // name={`templates.${selectedIndex}.contentCht`} | |||||
| // render={({ field }) => ( | |||||
| // <MailField | |||||
| // content={field.value} | |||||
| // onChange={field.onChange} | |||||
| // error={Boolean(errors.templates?.[selectedIndex]?.contentCht)} | |||||
| // /> | |||||
| // )} | |||||
| // rules={{ | |||||
| // required: requiredFields.includes(name), | |||||
| // }} | |||||
| // /> | |||||
| // </Grid> | |||||
| // ) | |||||
| // default: | |||||
| // return ( | |||||
| // <Grid item xs={8}> | |||||
| // <TextField | |||||
| // label={t(name)} | |||||
| // fullWidth | |||||
| // {...register(`templates.${selectedIndex}.cc`), | |||||
| // { | |||||
| // required: requiredFields.includes(name) | |||||
| // }} | |||||
| // /> | |||||
| // </Grid> | |||||
| // ) | |||||
| // } | |||||
| // }) | |||||
| // }, [fields]) | |||||
| return ( | |||||
| <Card sx={{ display: isActive ? "block" : "none" }}> | |||||
| <CardContent component={Stack} spacing={4}> | |||||
| <Box> | |||||
| <Typography variant="overline" display="block" marginBlockEnd={1}> | |||||
| {t("Template")} | |||||
| </Typography> | |||||
| <Grid container spacing={2} columns={{ xs: 6, sm: 12 }}> | |||||
| <Grid item xs={8}> | |||||
| <Autocomplete | |||||
| disableClearable | |||||
| options={options} | |||||
| value={options[selectedIndex]} | |||||
| onChange={makeAutocompleteChangeHandler} | |||||
| groupBy={(option) => ( | |||||
| option.group && option.group.trim() !== '' ? option.group : 'Ungrouped' | |||||
| )} | |||||
| renderGroup={(params) => ( | |||||
| <React.Fragment> | |||||
| <ListSubheader>{params.group}</ListSubheader> | |||||
| {params.children} | |||||
| </React.Fragment> | |||||
| )} | |||||
| renderOption={( | |||||
| params: React.HTMLAttributes<HTMLLIElement> & { key?: React.Key }, | |||||
| option, | |||||
| { selected }, | |||||
| ) => { | |||||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | |||||
| const { key, ...rest } = params; | |||||
| return ( | |||||
| <MenuItem | |||||
| {...rest} | |||||
| disableRipple | |||||
| value={option.value} | |||||
| > | |||||
| {option.label} | |||||
| </MenuItem> | |||||
| ); | |||||
| }} | |||||
| renderInput={(params) => <TextField {...params} variant="outlined" label={t("Select Template (View By Code - Description)")} />} | |||||
| /> | |||||
| </Grid> | |||||
| <Grid item xs={8}> | |||||
| <TextField | |||||
| label={t("Code")} | |||||
| fullWidth | |||||
| {...register(`templates.${selectedIndex}.code`, { | |||||
| required: "Code is required!" | |||||
| })} | |||||
| required | |||||
| error={Boolean(errors.templates?.[selectedIndex]?.code)} | |||||
| /> | |||||
| </Grid> | |||||
| <Grid item xs={8}> | |||||
| <TextField | |||||
| label={t("Description")} | |||||
| fullWidth | |||||
| {...register(`templates.${selectedIndex}.description`, { | |||||
| required: "Description is required!" | |||||
| })} | |||||
| required | |||||
| error={Boolean(errors.templates?.[selectedIndex]?.description)} | |||||
| /> | |||||
| </Grid> | |||||
| {/* <Grid item xs={8}> | |||||
| <TextField | |||||
| label={t("To")} | |||||
| fullWidth | |||||
| {...register(`templates.${selectedIndex}.to`, { | |||||
| required: "To is required!" | |||||
| })} | |||||
| required | |||||
| error={Boolean(errors.templates?.[selectedIndex]?.to)} | |||||
| /> | |||||
| </Grid> | |||||
| <Grid item xs={8}> | |||||
| <TextField | |||||
| label={t("Cc")} | |||||
| fullWidth | |||||
| {...register(`templates.${selectedIndex}.cc`)} | |||||
| /> | |||||
| </Grid> | |||||
| <Grid item xs={8}> | |||||
| <TextField | |||||
| label={t("Required Params (split by ',')")} | |||||
| fullWidth | |||||
| {...register(`templates.${selectedIndex}.params`)} | |||||
| /> | |||||
| </Grid> */} | |||||
| <Grid item xs={8}> | |||||
| <TextField | |||||
| label={t("Subject CHT")} | |||||
| fullWidth | |||||
| {...register(`templates.${selectedIndex}.subjectCht`, | |||||
| { | |||||
| required: "Mail Subject is required!", | |||||
| })} | |||||
| required | |||||
| error={Boolean(errors.templates?.[selectedIndex]?.subjectCht)} | |||||
| /> | |||||
| </Grid> | |||||
| <Grid item xs={12}> | |||||
| <Controller | |||||
| control={control} | |||||
| name={`templates.${selectedIndex}.contentCht`} | |||||
| render={({ field }) => ( | |||||
| <MailField | |||||
| content={field.value} | |||||
| onChange={field.onChange} | |||||
| error={Boolean(errors.templates?.[selectedIndex]?.contentCht)} | |||||
| /> | |||||
| )} | |||||
| rules={{ | |||||
| required: "Mail Content is required!", | |||||
| }} | |||||
| /> | |||||
| </Grid> | |||||
| </Grid> | |||||
| </Box> | |||||
| </CardContent> | |||||
| </Card> | |||||
| ); | |||||
| }; | |||||
| export default TemplateDetails; | |||||