Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added product code screen #19

Merged
merged 1 commit into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/helpers/permission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type PermissionString =
| "productUnit"
| "productCategory"
| "productBrand"
| "productCode"
| "productWarranty";
export type IPermission = Record<PermissionString, Record<PermissionOperation, number>>;
export const permissionOperations: PermissionOperation[] = ["create", "read", "update", "delete"];
Expand All @@ -29,7 +30,8 @@ export const PERMISSIONS_LIST: PermissionString[] = [
"faqs",
"productCategory",
"productBrand",
"productUnit"
"products",
"productCode"
];

export const PERMISSIONS = structurePermissionsObject(PERMISSIONS_LIST);
Expand Down
9 changes: 9 additions & 0 deletions src/interfaces/productCode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { DefaultPluginProps } from ".";

export interface ProductCodeProps extends DefaultPluginProps {
code: string;
slug?: string;
description?: string;
accountId: string;
wareHouseId?: string;
}
72 changes: 72 additions & 0 deletions src/pages/productCodes/CreateProductCodeScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { HandlerProps } from "@/components/customFields/type";
import { useGeneralMutation } from "@/hooks/request/useGeneralMutation";
import { useError } from "@/hooks/useError";
import { useFormFieldUpdate } from "@/hooks/useFormFieldUpdate";
import { Validator } from "@/validator";
import { useNavigate } from "react-router-dom";
import { toast } from "sonner";
import EditProductCodeFields from "./EditProductCodeFields";

const CreateProductCodeScreen = () => {
const buttonTitle = "Create";
const defaultData = {
description: "",
code: ""
};
const { addErrors, errors, resetError } = useError<typeof defaultData>();
const { formValues, updateFormFieldValue } = useFormFieldUpdate(defaultData);
const navigate = useNavigate();
const { isPending, mutate } = useGeneralMutation({
httpMethod: "post",
mutationKey: ["createProductCode"],
url: "/product-codes"
});
const validator = new Validator({
formData: formValues,
rules: {
description: "required|minLength:10",
code: "required:minLength:5"
}
});

const handleFormFieldChange = (data: HandlerProps) => {
const { key, value } = data;
updateFormFieldValue(key, value);
};

const onsubmitHandler = () => {
validator.validate();

if (validator.failed()) {
return addErrors(validator.getValidationErrorsByIndex());
} else {
resetError();
}

mutate(
{ payload: formValues },
{
onSuccess() {
toast.success("Success", {
description: "Product code created"
});
navigate("/product-codes");
}
}
);
};

return (
<EditProductCodeFields
pageTitle="Create Product Code"
buttonTitle={buttonTitle}
formFields={formValues}
handleFormFieldChange={handleFormFieldChange}
onsubmitHandler={onsubmitHandler}
errors={errors as Record<string, any>}
isLoading={isPending}
/>
);
};

export default CreateProductCodeScreen;
67 changes: 67 additions & 0 deletions src/pages/productCodes/EditProductCodeFields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import Container from "@/components/Container";
import PrimaryButton from "@/components/PrimaryButton";
import InputField from "@/components/customFields/input/InputField";
import TextAreaField from "@/components/customFields/input/TextAreaField";
import { HandlerProps } from "@/components/customFields/type";
import DashboardLayout from "@/components/dashboard/Layout";
import { FC } from "react";

interface EditProductCodeFieldsProps {
buttonTitle: string;
formFields: Record<string, any>;
onsubmitHandler: () => void;
handleFormFieldChange: (data: HandlerProps) => void;
errors?: Record<string, string>;
isLoading?: boolean;
pageTitle?: string;
disabledButton?: boolean;
}
const EditProductCodeFields: FC<EditProductCodeFieldsProps> = ({
handleFormFieldChange,
onsubmitHandler,
formFields,
errors,
isLoading,
buttonTitle,
pageTitle,
disabledButton
}) => {
return (
<DashboardLayout pageTitle="Create Product Code" pageDescription="Fill the details to create a product code">
<Container className="border border-gray-50">
<h1>{pageTitle}</h1>
<div className="space-y-5">
<InputField
name="code"
handleInputChange={handleFormFieldChange}
label="Code"
isRequired
errorMessage={errors?.code}
value={formFields?.code}
disabled={isLoading}
/>
<TextAreaField
name="description"
handleInputChange={handleFormFieldChange}
label="Code description"
isRequired
errorMessage={errors?.description}
value={formFields?.description}
disabled={isLoading}
/>
<div className="flex items-center justify-end">
<PrimaryButton
text={buttonTitle}
onClick={onsubmitHandler}
loading={isLoading}
disabled={disabledButton || isLoading}
className="md:w-[200px]"
/>
</div>
</div>
</Container>
</DashboardLayout>
);
};

export default EditProductCodeFields;
120 changes: 120 additions & 0 deletions src/pages/productCodes/ListProductCodesScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import Container from "@/components/Container";
import Modal from "@/components/Modal";
import DashboardLayout from "@/components/dashboard/Layout";
import Table from "@/components/table/Table";
import { useGeneralMutation } from "@/hooks/request/useGeneralMutation";
import { useGeneralQuery } from "@/hooks/request/useGeneralQuery";
import { useOptimisticUpdates } from "@/hooks/request/useOptimisticUpdates";
import { GetManyProps } from "@/hooks/types";
import { useSetQueryParam } from "@/hooks/useSetQueryParam";
import { ModalActionButtonProps } from "@/interfaces";
import { ProductCodeProps } from "@/interfaces/productCode";
import { productCodeSchema } from "@/tableSchema/productCodes";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { toast } from "sonner";

const ListProductCodeScreen = () => {
const { removeItemFromList } = useOptimisticUpdates();
const [selectedCode, setSelectedCode] = useState<Record<string, any>>({});
const { queryObject } = useSetQueryParam();
const { mutate, isPending } = useGeneralMutation<ProductCodeProps>({
httpMethod: "delete",
mutationKey: ["deleteProductCode", selectedCode.id],
url: `/product-codes/${selectedCode.id}`
});

const { data, isFetching } = useGeneralQuery<GetManyProps<ProductCodeProps>>({
queryKey: ["productCodes", queryObject],
url: "/product-codes",
query: queryObject,
enabled: !!Object.keys(queryObject).length
});
const [openModal, setOpenModal] = useState(false);
const navigate = useNavigate();
const rowActions = [
{
label: "Edit",
action: handleEditRowActionClick
},
{
label: "Delete",
action: (data: Record<string, any>) => {
setOpenModal(true);
setSelectedCode(data);
}
}
];

const modalData = {
showModal: openModal,
modalTitle: (code: string) => {
console.log({ code });

return `Are you sure you want to delete ${code}`;
},
modalDescription: `Deleting the product code will permanently remove it from the system. Continue?`,
actionButtons: [
{
title: "Cancel",
action: () => setOpenModal(false),
type: "cancel"
},
{
title: "Continue",
action: async () => {
mutate(selectedCode.id, {
onSuccess: () => {
setOpenModal(false);
toast.success("Success", {
description: "Product code deleted"
});
},
onSettled() {
return removeItemFromList(["productCodes", queryObject], selectedCode.id);
}
});
},
type: "action",
loading: isPending
}
] as ModalActionButtonProps[]
};

function handleEditRowActionClick(data: Record<string, any>) {
navigate(`/product-codes/${data.id}`);
}

return (
<DashboardLayout
pageTitle="Product Codes"
actionButton={{
createButton: { name: "Create Product Code", onClick: () => navigate("/product-codes/create") }
}}
>
<Modal
showModal={modalData.showModal}
modalTitle={modalData.modalTitle(selectedCode.code)}
modalDescription={modalData.modalDescription}
actionButtons={modalData.actionButtons}
/>
<Container className="border border-gray-50">
<Table
columns={productCodeSchema}
data={data?.data || []}
isLoading={isFetching}
loadingText="Fetching product code data"
showExportButton
paginator={data?.paginator}
filters={[]}
actionButtons={rowActions}
allowRowSelect
handleRowClick={handleEditRowActionClick}
showSelectColumns
/>
</Container>
</DashboardLayout>
);
};

export default ListProductCodeScreen;
89 changes: 89 additions & 0 deletions src/pages/productCodes/UpdateProductCodeScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { HandlerProps } from "@/components/customFields/type";
import { useGeneralMutation } from "@/hooks/request/useGeneralMutation";
import { useError } from "@/hooks/useError";
import { useFormFieldUpdate } from "@/hooks/useFormFieldUpdate";
import { Validator } from "@/validator";
import { useNavigate, useParams } from "react-router-dom";
import { toast } from "sonner";
import { useGeneralQuery } from "@/hooks/request/useGeneralQuery";
import { objectDifference } from "@/helpers";
import { useEffect } from "react";
import EditProductCodeFields from "./EditProductCodeFields";
import { ProductCodeProps } from "@/interfaces/productCode";

interface ValidatorProps {
code: string;
description: string;
}
const UpdateProductCodeScreen = () => {
const params = useParams<{ id: string }>();
const categoryId = params.id;
const buttonTitle = "Update";
const { addErrors, errors, resetError } = useError<ValidatorProps>();
const { data } = useGeneralQuery<ProductCodeProps>({
queryKey: ["productCode", categoryId],
url: `/product-codes/${categoryId}`
});

const { formValues, updateFormFieldValue, setFormValues } = useFormFieldUpdate(data);
const navigate = useNavigate();
const { isPending, mutate } = useGeneralMutation({
httpMethod: "put",
mutationKey: ["updateCode", categoryId as string],
url: `/product-codes/${categoryId}`
});
const validator = new Validator<Partial<ValidatorProps>>({
formData: formValues as ValidatorProps,
rules: {
description: "required|minLength:10",
code: "required:minLength:5"
}
});

const handleFormFieldChange = (data: HandlerProps) => {
const { key, value } = data;
updateFormFieldValue(key, value);
};

const payload = objectDifference(data, formValues);
const onsubmitHandler = () => {
validator.validate();

if (validator.failed()) {
return addErrors(validator.getValidationErrorsByIndex());
} else {
resetError();
}

mutate(
{ payload },
{
onSuccess() {
toast.success("Success", {
description: "Product code created"
});
navigate("/product-codes");
}
}
);
};
useEffect(() => {
if (data) {
setFormValues(data);
}
}, [params.id, data]);
return (
<EditProductCodeFields
pageTitle="Create Product Code"
buttonTitle={buttonTitle}
formFields={formValues as Record<string, any>}
handleFormFieldChange={handleFormFieldChange}
onsubmitHandler={onsubmitHandler}
errors={errors as Record<string, any>}
isLoading={isPending}
disabledButton={!Object.keys(payload).length}
/>
);
};

export default UpdateProductCodeScreen;
Loading