Skip to content

Commit

Permalink
feat: create predict
Browse files Browse the repository at this point in the history
  • Loading branch information
ridhlab committed Jan 2, 2024
1 parent 44a732a commit a216b85
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/common/breadcrumb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const Breadcrumbs = {
Index: () => [{ label: "Result Predict", href: Routes.ResultIndex }],
Create: () => [
{ label: "Result Predict", href: Routes.ResultIndex },
{ label: "Create", href: Routes.ResultCreate },
{ label: "Predict", href: Routes.ResultCreate },
],
Detail: (id) => [
{ label: "Result Predict", href: Routes.ResultIndex },
Expand Down
67 changes: 67 additions & 0 deletions src/components/modules/Result/ModalResultPredict.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import Button from "@/components/shared/Button/Button";
import { getDecimalPlace } from "@/helpers/number";
import { parsingRoute } from "@/helpers/route";
import { IPredict } from "@/interfaces/responses/Result";
import { Routes } from "@/routes/routes";
import { EyeOutlined } from "@ant-design/icons";
import { Modal, Space, Table } from "antd";
import { ColumnsType } from "antd/es/table";
import React from "react";

interface IProps {
open: boolean;
closeModal: () => void;
dataPredict: IPredict;
}

const ModalResultPredict: React.FC<IProps> = ({
open,
closeModal,
dataPredict,
}) => {
const footer = (
<Space>
<Button onClick={closeModal}>Close</Button>
<Button
icon={<EyeOutlined />}
href={parsingRoute(Routes.ResultDetail, {
id: dataPredict?.resultId,
})}
>
See Detail
</Button>
</Space>
);

const columns: ColumnsType = [
{
title: "Variable Output",
dataIndex: "variableOutputName",
},
{
title: "Value",
dataIndex: "value",
render: (value) => getDecimalPlace(value, 3),
},
];

return (
<Modal
open={open}
centered
closable={false}
title={`Result predict for ${dataPredict?.name}`}
footer={footer}
>
<Table
bordered
pagination={false}
size="small"
dataSource={dataPredict?.predict}
columns={columns}
/>
</Modal>
);
};

export default ModalResultPredict;
4 changes: 4 additions & 0 deletions src/interfaces/requests/Result/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface IPredictRequest {
name: string;
dataInput: { variableInputId: number; value: number }[];
}
11 changes: 11 additions & 0 deletions src/interfaces/responses/Result/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,14 @@ import { IBaseResponse } from "../base";

export interface IResultListResponse extends IBaseResponse<IResult[]> {}
export interface IResultDetailResponse extends IBaseResponse<IResult> {}

export interface IPredict {
resultId: number;
name: string;
predict: {
variableOutputId: number;
variableOutputName: string;
value: number;
}[];
}
export interface IResultPredictResponse extends IBaseResponse<IPredict> {}
152 changes: 152 additions & 0 deletions src/pages/Result/Create.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { Breadcrumbs } from "@/common/breadcrumb";
import ModalResultPredict from "@/components/modules/Result/ModalResultPredict";
import Button from "@/components/shared/Button/Button";
import ButtonAction from "@/components/shared/Form/ButtonActions";
import LoaderCenter from "@/components/shared/Loader/LoaderCenter";
import { getRequiredMessage } from "@/helpers/form";
import { modalConfirm } from "@/helpers/modal-confirm";
import { useFormUtility } from "@/hooks/useFormUtility";
import { IPredictRequest } from "@/interfaces/requests/Result";
import { IPredict } from "@/interfaces/responses/Result";
import MainLayout from "@/layouts/MainLayout";
import { Routes } from "@/routes/routes";
import { useResultPredictMutation } from "@/services/mutation/Result";
import { useVariableInputQueryIndex } from "@/services/query/VariableInput";
import { Card, Flex, Form, Input, InputNumber } from "antd";
import React from "react";
import * as yup from "yup";

const schema = yup.object().shape({
name: yup.string().required(getRequiredMessage("Name")),
dataInput: yup
.array()
.of(
yup.object().shape({
variableInputId: yup
.number()
.required(getRequiredMessage("Variable Input"))
.defined(),
value: yup
.number()
.required(getRequiredMessage("Value"))
.defined(),
})
)
.required(),
});

const ResultCreate: React.FC = () => {
const { form, yupSync } = useFormUtility({ schema });
const queryVariableInput = useVariableInputQueryIndex();

const [openModalResultPredict, setOpenModalResultPredict] =
React.useState(false);
const [resultPredict, setResultPredict] = React.useState<IPredict>(null);

const mutationPredict = useResultPredictMutation({
onSuccess: ({ data }) => {
setOpenModalResultPredict(true);
setResultPredict(data);
},
});

const closeModal = () => {
setOpenModalResultPredict(false);
setResultPredict(null);
};

const onFinish = async () => {
await form.validateFields();
modalConfirm({
onOk: () => {
const dataSubmitted = form.getFieldsValue();
mutationPredict.mutate(dataSubmitted as IPredictRequest);
},
});
};

const getLabelOutput = (idContext) => {
return queryVariableInput?.data?.data?.find(
({ id }) => id === idContext
)?.name;
};

const formListDataInput = (
<Form.List name="dataInput">
{(fields) =>
fields.map((field) => (
<React.Fragment key={field.key}>
<Form.Item
required
label={getLabelOutput(
form.getFieldValue([
"dataInput",
field.name,
"variableInputId",
])
)}
name={[field.name, "value"]}
rules={[yupSync]}
>
<InputNumber />
</Form.Item>
<Form.Item
name={[field.name, "variableInputId"]}
></Form.Item>
</React.Fragment>
))
}
</Form.List>
);

return (
<MainLayout title="Predict" breadcrumbs={Breadcrumbs.Result.Create()}>
<Card>
{queryVariableInput.isLoading ||
queryVariableInput.isFetching ? (
<LoaderCenter />
) : (
<Form
form={form}
onFinish={onFinish}
initialValues={{
name: "",
dataInput: queryVariableInput?.data?.data?.map(
({ id }) => ({ variableInputId: id, value: 0 })
),
}}
>
<Form.Item
required
label="Name"
name="name"
rules={[yupSync]}
>
<Input />
</Form.Item>
<Flex wrap="wrap" style={{ columnGap: "1rem" }}>
{formListDataInput}
</Flex>
<ButtonAction
actions={[
<Button href={Routes.ResultIndex}>
Cancel
</Button>,
<Button type="primary" htmlType="submit">
Predict
</Button>,
]}
/>
</Form>
)}
</Card>
<ModalResultPredict
open={openModalResultPredict}
closeModal={closeModal}
dataPredict={resultPredict}
/>
</MainLayout>
);
};

export default ResultCreate;
9 changes: 8 additions & 1 deletion src/pages/Result/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Breadcrumbs } from "@/common/breadcrumb";
import Button from "@/components/shared/Button/Button";
import LoaderCenter from "@/components/shared/Loader/LoaderCenter";
import RowActionButtons from "@/components/shared/Table/RowActionButtons";
import { parsingRoute } from "@/helpers/route";
Expand Down Expand Up @@ -38,7 +39,13 @@ const ResultIndex: React.FC = () => {
];
return (
<MainLayout title="Result" breadcrumbs={Breadcrumbs.Result.Index()}>
<Card>
<Card
extra={
<Button href={Routes.ResultCreate} type="primary">
Create
</Button>
}
>
{query.isLoading || query.isFetching ? (
<LoaderCenter />
) : (
Expand Down
9 changes: 9 additions & 0 deletions src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const MatrixCompareEditByInputPage = React.lazy(
);

const ResultIndexPage = React.lazy(() => import("@/pages/Result"));
const ResultCreatePage = React.lazy(() => import("@/pages/Result/Create"));

export const withSuspense = (component: ReactNode) => {
return <Suspense fallback={<LoaderFullscreen />}>{component}</Suspense>;
Expand Down Expand Up @@ -134,4 +135,12 @@ export const router = createBrowserRouter([
</PrivateRoute>
),
},
{
path: Routes.ResultCreate,
element: withSuspense(
<PrivateRoute>
<ResultCreatePage />
</PrivateRoute>
),
},
]);
13 changes: 13 additions & 0 deletions src/services/apis/Result/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AxiosError } from "axios";
import { axiosAuthInstance } from "..";
import { EndpointApi } from "@/routes/routes";
import { IPredictRequest } from "@/interfaces/requests/Result";

export const resultGetByUserLogin = async () => {
try {
Expand All @@ -12,3 +13,15 @@ export const resultGetByUserLogin = async () => {
throw (error as AxiosError).response.data;
}
};

export const resultPredict = async (payload: IPredictRequest) => {
try {
const response = await axiosAuthInstance.post(
EndpointApi.ResultPredict,
payload
);
return response.data;
} catch (error) {
throw (error as AxiosError).response.data;
}
};
19 changes: 19 additions & 0 deletions src/services/mutation/Result/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { IPredictRequest } from "@/interfaces/requests/Result";
import { IResultPredictResponse } from "@/interfaces/responses/Result";
import { IBaseResponse } from "@/interfaces/responses/base";
import { resultPredict } from "@/services/apis/Result";
import { UseMutationOptions, useMutation } from "@tanstack/react-query";

export const useResultPredictMutation = (
options?: UseMutationOptions<
IResultPredictResponse,
IBaseResponse<unknown>,
IPredictRequest
>
) => {
return useMutation({
mutationKey: ["result-predict"],
mutationFn: (payload) => resultPredict(payload),
...options,
});
};

0 comments on commit a216b85

Please sign in to comment.