feat(FE): add drawer ui store

This commit is contained in:
randy-ar
2025-12-01 10:13:28 +07:00
parent 892bb19dfd
commit 2ace95a0db
6 changed files with 89 additions and 9 deletions
+9 -6
View File
@@ -4,6 +4,7 @@ import { usePathname, useRouter } from 'next/navigation';
import Drawer from '@/components/Drawer';
import React, { ReactNode } from 'react';
import ProjectFlockTable from '@/components/pages/production/project-flock/ProjectFlockTable';
import { useUiStore } from '@/stores/ui/ui.store';
export default function ProjectFlockLayout({
children,
@@ -12,6 +13,7 @@ export default function ProjectFlockLayout({
}) {
const pathname = usePathname();
const router = useRouter();
const toggleValidate = useUiStore((s) => s.toggleValidate);
const isAdd = pathname.endsWith('/add');
const isEdit = pathname.includes('/detail/edit');
@@ -23,13 +25,14 @@ export default function ProjectFlockLayout({
// const childRef = useRef<ProjectFlockFormRef>(null);
const handleBackdropClick = () => {
// const isValid = childRef.current?.validate(); // 🔥 trigger validation child
const unsub = useUiStore.getState().subscribeIsValid((isValid) => {
if (isValid) {
unsub(); // berhenti listen
router.push('/production/project-flock');
}
});
// if (!isValid) {
// toast.error('Form belum valid, Drawer tidak bisa close');
// return;
// }
router.push('/production/project-flock');
toggleValidate();
};
return (
+2 -2
View File
@@ -7,11 +7,11 @@ import {
useState,
} from 'react';
import { cn, formatDate } from '@/lib/helper';
import Modal, { useModal } from '../Modal';
import { DateRange, DayPicker, Matcher } from 'react-day-picker';
import 'react-day-picker/dist/style.css';
import Button from '../Button';
import { Icon } from '@iconify/react';
import Modal, { useModal } from '@/components/Modal';
import Button from '@/components/Button';
export interface DateInputProps {
label?: string;
@@ -43,6 +43,7 @@ import { PROJECT_FLOCK_APPROVAL_LINE } from '@/config/approval-line';
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
import NumberInput from '@/components/input/NumberInput';
import Card from '@/components/Card';
import { useUiStore } from '@/stores/ui/ui.store';
interface ProjectFlockFormProps {
formType?: 'add' | 'edit' | 'detail';
@@ -79,6 +80,8 @@ const ProjectFlockForm = ({
initialValues?.flock_name?.lastIndexOf(' ')
) ?? ''
);
const subscribeValidate = useUiStore((s) => s.subscribeValidate);
const setIsValid = useUiStore((s) => s.setIsValid);
const deleteModal = useModal();
const confirmModal = useModal();
@@ -577,6 +580,29 @@ const ProjectFlockForm = ({
// return isValid;
// },
// }));
useEffect(() => {
const unsub = subscribeValidate(() => {
formik.validateForm().then((errors) => {
if (Object.keys(errors).length > 0) {
// Membentuk touched object yang strongly-typed
const touched = Object.keys(formik.values).reduce<
Record<keyof typeof formik.values, boolean>
>(
(acc, key) => {
acc[key as keyof typeof formik.values] = true;
return acc;
},
{} as Record<keyof typeof formik.values, boolean>
);
formik.setTouched(touched, true);
}
setIsValid(Object.keys(errors).length === 0);
});
});
return unsub;
}, []);
return (
<>
+40
View File
@@ -0,0 +1,40 @@
import { StateCreator } from 'zustand';
import { DrawerUiSlice } from '@/types/stores';
export const createFormDrawerUiSlice: StateCreator<
DrawerUiSlice,
[],
[],
DrawerUiSlice
> = (set, get, api) => ({
// event flag untuk memicu formik validate
triggerValidate: false,
// dibalik untuk memicu event
toggleValidate: () => {
const current = get().triggerValidate;
set({ triggerValidate: !current });
},
// sistem subscriber sederhana agar form bisa listen perubahan flag
subscribeValidate: (callback: () => void) => {
let prev = get().triggerValidate;
const unsub = api.subscribe((state) => {
if (state.triggerValidate !== prev) {
prev = state.triggerValidate;
callback();
}
});
return unsub;
},
isValid: false,
setIsValid: (isValid: boolean) => set({ isValid }),
subscribeIsValid: (callback: (isValid: boolean) => void) => {
return api.subscribe((state) => {
callback(Boolean(state.isValid));
});
},
});
+2
View File
@@ -5,11 +5,13 @@ import { devtools } from 'zustand/middleware';
import { UIStore } from '@/types/stores';
import { createMainUiSlice } from '@/stores/ui/slices/main.slice';
import { createFormDrawerUiSlice } from '@/stores/ui/slices/drawer.slice';
export const useUiStore = create<UIStore>()(
devtools(
(...args) => ({
...createMainUiSlice(...args),
...createFormDrawerUiSlice(...args),
}),
{
name: 'UIStore',
+10 -1
View File
@@ -3,4 +3,13 @@ type MainUiSlice = {
setMainDrawerOpen: (open: boolean) => void;
};
export type UIStore = MainUiSlice;
type DrawerUiSlice = {
triggerValidate: boolean;
toggleValidate: () => void;
subscribeValidate: (callback: () => void) => void;
isValid: boolean;
setIsValid: (v: boolean) => void;
subscribeIsValid: (callback: (isValid: boolean) => void) => () => void;
};
export type UIStore = MainUiSlice & DrawerUiSlice;