Quellcode durchsuchen

[M18 Import Testing] Add import m18 po

production_process
cyril.tsui vor 2 Monaten
Ursprung
Commit
181b0048a4
11 geänderte Dateien mit 294 neuen und 1 gelöschten Zeilen
  1. +19
    -1
      package.json
  2. +30
    -0
      src/app/(main)/settings/importTesting/page.tsx
  3. +21
    -0
      src/app/api/settings/importTesting/actions.ts
  4. +1
    -0
      src/app/api/settings/importTesting/index.ts
  5. +5
    -0
      src/app/utils/formatUtil.ts
  6. +1
    -0
      src/components/Breadcrumb/Breadcrumb.tsx
  7. +127
    -0
      src/components/ImportTesting/ImportPo.tsx
  8. +67
    -0
      src/components/ImportTesting/ImportTesting.tsx
  9. +17
    -0
      src/components/ImportTesting/ImportTestingWrapper.tsx
  10. +1
    -0
      src/components/ImportTesting/index.ts
  11. +5
    -0
      src/components/NavigationContent/NavigationContent.tsx

+ 19
- 1
package.json Datei anzeigen

@@ -19,7 +19,24 @@
"@mui/material-nextjs": "^5.15.0",
"@mui/x-data-grid": "^6.18.7",
"@mui/x-date-pickers": "^6.18.7",
"@tiptap/react": "^2.12.0",
"@tiptap/core": "^2.14.0",
"@tiptap/extension-color": "^2.14.0",
"@tiptap/extension-document": "^2.14.0",
"@tiptap/extension-gapcursor": "^2.14.0",
"@tiptap/extension-highlight": "^2.14.0",
"@tiptap/extension-list-item": "^2.14.0",
"@tiptap/extension-paragraph": "^2.14.0",
"@tiptap/extension-table": "^2.14.0",
"@tiptap/extension-table-cell": "^2.14.0",
"@tiptap/extension-table-header": "^2.14.0",
"@tiptap/extension-table-row": "^2.14.0",
"@tiptap/extension-text": "^2.14.0",
"@tiptap/extension-text-align": "^2.14.0",
"@tiptap/extension-text-style": "^2.14.0",
"@tiptap/extension-underline": "^2.14.0",
"@tiptap/pm": "^2.14.0",
"@tiptap/react": "^2.14.0",
"@tiptap/starter-kit": "^2.14.0",
"@unly/universal-language-detector": "^2.0.3",
"apexcharts": "^3.45.2",
"axios": "^1.9.0",
@@ -28,6 +45,7 @@
"i18next": "^23.7.11",
"i18next-resources-to-backend": "^1.2.0",
"lodash": "^4.17.21",
"mui-color-input": "^7.0.0",
"next": "14.0.4",
"next-auth": "^4.24.5",
"next-pwa": "^5.6.0",


+ 30
- 0
src/app/(main)/settings/importTesting/page.tsx Datei anzeigen

@@ -0,0 +1,30 @@
import ImportTesting from "@/components/ImportTesting";
import { getServerI18n } from "@/i18n";
import { Stack } from "@mui/material";
import { Metadata } from "next";
import React, { Suspense } from "react";

export const metadata: Metadata = {
title: "Import Testing"
}

const ImportTestingPage: React.FC = async () => {
const { t } = await getServerI18n("importTesting");

return (
<>
<Stack
direction="row"
justifyContent="space-between"
flexWrap="wrap"
rowGap={2}
>
</Stack>
<Suspense fallback={<ImportTesting.Loading />}>
<ImportTesting />
</Suspense>
</>
)
}

export default ImportTestingPage;

+ 21
- 0
src/app/api/settings/importTesting/actions.ts Datei anzeigen

@@ -0,0 +1,21 @@
"use server";

import { serverFetchWithNoContent } from '@/app/utils/fetchUtil';
import { BASE_API_URL } from "@/config/api";

export interface ImportPoForm {
dateFrom: string,
dateTo: string,
}

export interface ImportTestingForm {
po: ImportPoForm
}

export const testImportPo = async (data: ImportPoForm) => {
return serverFetchWithNoContent(`${BASE_API_URL}/m18/po`, {
method: "POST",
body: JSON.stringify(data),
headers: { "Content-Type": "application/json" },
})
}

+ 1
- 0
src/app/api/settings/importTesting/index.ts Datei anzeigen

@@ -0,0 +1 @@
// "server only"

+ 5
- 0
src/app/utils/formatUtil.ts Datei anzeigen

@@ -49,6 +49,11 @@ export const dateStringToDayjs = (date: string) => {
return dayjs(date, OUTPUT_DATE_FORMAT)
}

export const dateTimeStringToDayjs = (dateTime: string) => {
// Format: YYYY/MM/DD HH:mm:ss
return dayjs(dateTime, `${OUTPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`)
}

export const stockInLineStatusMap: { [status: string]: number } = {
"draft": 0,
"pending": 1,


+ 1
- 0
src/components/Breadcrumb/Breadcrumb.tsx Datei anzeigen

@@ -19,6 +19,7 @@ const pathToLabelMap: { [path: string]: string } = {
"/scheduling/detail": "Detail Scheduling",
"/scheduling/detail/edit": "FG Production Schedule",
"/inventory": "Inventory",
"/settings/importTesting": "Import Testing",
};

const Breadcrumb = () => {


+ 127
- 0
src/components/ImportTesting/ImportPo.tsx Datei anzeigen

@@ -0,0 +1,127 @@
"use client"
import { ImportTestingForm } from "@/app/api/settings/importTesting/actions";
import { ImportPoForm } from "@/app/api/settings/importTesting/actions";
import { INPUT_DATE_FORMAT, OUTPUT_DATE_FORMAT, OUTPUT_TIME_FORMAT, dateTimeStringToDayjs } from "@/app/utils/formatUtil";
import { Check } from "@mui/icons-material";
import { Box, Button, Card, CardContent, FormControl, Grid, Stack, Typography } from "@mui/material";
import { DatePicker, DateTimePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import dayjs, { Dayjs } from "dayjs";
import React, { useCallback, useState } from "react";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";

interface Props {
}

const ImportPo: React.FC<Props> = ({
}) => {

const { t } = useTranslation()
const [isLoading, setIsLoading] = useState(false)
const {
control,
formState: { errors },
watch
} = useFormContext<ImportTestingForm>()

const handleDateTimePickerOnChange = useCallback((value: Dayjs | null, onChange: (value: any) => void) => {
const formattedValue = value ? value.format(`${INPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`) : null
onChange(formattedValue)
}, [])



return (
<Card sx={{ width: '100%' }}>
<CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
<Grid container>
<Grid container>
<Typography variant="overline">{t("Import PO")}</Typography>
</Grid>
<Grid item xs={8}>
<LocalizationProvider
dateAdapter={AdapterDayjs}
// TODO: Should maybe use a custom adapterLocale here to support YYYY-MM-DD
adapterLocale="zh-hk"
>
<Box display="flex">
<Controller
control={control}
name="po.dateFrom"
rules={{
required: "Please input the date From!",
validate: {
isValid: (value) =>
value && dateTimeStringToDayjs(value).isValid() ? true : "Invalid date-time"
},
}}
render={({ field, fieldState: { error } }) => (
<DateTimePicker
label={t("Import Po From")}
format={`${OUTPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`}
onChange={(newValue: Dayjs | null) => (handleDateTimePickerOnChange(newValue, field.onChange))}
slotProps={{
textField: {
error: !!error,
helperText: error ? error.message : null
}
}}
/>
)}
/>
<Box
display="flex"
alignItems="center"
justifyContent="center"
marginInline={2}
>
{"-"}
</Box>
<Controller
control={control}
name="po.dateTo"
rules={{
required: "Please input the date to!",
validate: {
isValid: (value) =>
value && dateTimeStringToDayjs(value).isValid() ? true : "Invalid date-time",
isFuture: (value) =>
dateTimeStringToDayjs(value).isAfter(watch("po.dateFrom")) || "Date must be in the future",
},
}}
render={({ field, fieldState: { error } }) => (
<DateTimePicker
label={t("Import Po To")}
format={`${OUTPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`}
onChange={(newValue: Dayjs | null) => (handleDateTimePickerOnChange(newValue, field.onChange))}
slotProps={{
textField: {
error: !!error,
helperText: error ? error.message : null
}
}}
/>
)}
/>
</Box>
</LocalizationProvider>
</Grid>
</Grid>
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
name="importPo"
id="importPo"
variant="contained"
startIcon={<Check />}
type="submit"
>
{t("Import Po")}
</Button>
</Stack>
</CardContent>
</Card>
)
}

export default ImportPo;

+ 67
- 0
src/components/ImportTesting/ImportTesting.tsx Datei anzeigen

@@ -0,0 +1,67 @@
"use client"

import { ImportTestingForm, testImportPo } from "@/app/api/settings/importTesting/actions";
import { Card, CardContent, Grid, Stack, Typography } from "@mui/material";
import React, { BaseSyntheticEvent, FormEvent, useCallback, useState } from "react";
import { FormProvider, SubmitErrorHandler, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import ImportPo from "./ImportPo";
import { ImportPoForm } from "@/app/api/settings/importTesting/actions";

interface Props {

}

const ImportTesting: React.FC<Props> = ({

}) => {

const { t } = useTranslation()
const [isLoading, setIsLoading] = useState(false)
const formProps = useForm<ImportTestingForm>()

const onSubmit = useCallback(async (data: ImportTestingForm, event?: BaseSyntheticEvent) => {
const buttonId = (event?.nativeEvent as SubmitEvent).submitter?.id
console.log(data.po)
switch (buttonId) {
case "importPo":
setIsLoading(() => true)
const response = await testImportPo(data.po)
console.log(response)
if (response) {
setIsLoading(() => false)
}
break;
default:
break;
}
}, [])

const onSubmitError = useCallback<SubmitErrorHandler<ImportTestingForm>>(
(errors) => {
console.log(errors)
},
[],
);

return (
<Card>
<CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
<Typography variant="overline">{t("Status: ")}{isLoading ? t("Importing...") : t("Ready to import")}</Typography>
<FormProvider {...formProps}>
<Stack
spacing={2}
component={"form"}
onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)}
>
<Grid container>
<ImportPo />
</Grid>
</Stack>
</FormProvider>
</CardContent>
</Card>
)
}

export default ImportTesting;

+ 17
- 0
src/components/ImportTesting/ImportTestingWrapper.tsx Datei anzeigen

@@ -0,0 +1,17 @@
import React from "react";
import GeneralLoading from "../General/GeneralLoading"
import ImportTesting from "./ImportTesting";

interface SubComponents {
Loading: typeof GeneralLoading;
}

const ImportTestingWrapper: React.FC & SubComponents = async () => {
return <ImportTesting/>
}


ImportTestingWrapper.Loading = GeneralLoading;

export default ImportTestingWrapper

+ 1
- 0
src/components/ImportTesting/index.ts Datei anzeigen

@@ -0,0 +1 @@
export { default } from './ImportTestingWrapper'

+ 5
- 0
src/components/NavigationContent/NavigationContent.tsx Datei anzeigen

@@ -263,6 +263,11 @@ const NavigationContent: React.FC = () => {
label: "Mail",
path: "/settings/mail",
},
{
icon: <RequestQuote />,
label: "Import Testing",
path: "/settings/importTesting",
},
],
},
];


Laden…
Abbrechen
Speichern