diff --git a/src/app/marketing/add/delivery-orders/layout.tsx b/src/app/marketing/add/delivery-orders/layout.tsx deleted file mode 100644 index 7220dfa1..00000000 --- a/src/app/marketing/add/delivery-orders/layout.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import SuspenseHelper from '@/components/helper/SuspenseHelper'; - -const Layout = ({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) => { - return {children}; -}; - -export default Layout; diff --git a/src/app/marketing/add/delivery-orders/page.tsx b/src/app/marketing/add/delivery-orders/page.tsx deleted file mode 100644 index 4d92acda..00000000 --- a/src/app/marketing/add/delivery-orders/page.tsx +++ /dev/null @@ -1,54 +0,0 @@ -'use client'; - -import MarketingForm from '@/components/pages/marketing/form/MarketingForm'; -import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; -import { MarketingApi } from '@/services/api/marketing/marketing'; -import { useRouter, useSearchParams } from 'next/navigation'; -import toast from 'react-hot-toast'; -import useSWR from 'swr'; - -const EditMarketingDelivery = () => { - const router = useRouter(); - const searchParams = useSearchParams(); - - const soId = searchParams.get('marketingId'); - - const { - data: marketing, - isLoading: isLoading, - mutate: refreshMarketing, - } = useSWR(`get-so-${soId}`, () => - MarketingApi.getSingle(soId ? parseInt(soId) : 0) - ); - - if (!soId) { - router.back(); - - return ( -
- -
- ); - } - - if (!isLoading && (!marketing || isResponseError(marketing))) { - router.replace('/404'); - return; - } - - return ( -
- {isLoading && } - {!isLoading && isResponseSuccess(marketing) && ( - { - refreshMarketing(); - }} - /> - )} -
- ); -}; -export default EditMarketingDelivery; diff --git a/src/app/marketing/add/sales-orders/page.tsx b/src/app/marketing/add/sales-orders/page.tsx deleted file mode 100644 index 9e33d304..00000000 --- a/src/app/marketing/add/sales-orders/page.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import MarketingForm from '@/components/pages/marketing/form/MarketingForm'; - -const AddSalesOrder = () => { - return ( -
- -
- ); -}; - -export default AddSalesOrder; diff --git a/src/app/marketing/detail/delivery-orders/edit/layout.tsx b/src/app/marketing/detail/delivery-orders/edit/layout.tsx deleted file mode 100644 index 7220dfa1..00000000 --- a/src/app/marketing/detail/delivery-orders/edit/layout.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import SuspenseHelper from '@/components/helper/SuspenseHelper'; - -const Layout = ({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) => { - return {children}; -}; - -export default Layout; diff --git a/src/app/marketing/detail/delivery-orders/edit/page.tsx b/src/app/marketing/detail/delivery-orders/edit/page.tsx deleted file mode 100644 index 32625026..00000000 --- a/src/app/marketing/detail/delivery-orders/edit/page.tsx +++ /dev/null @@ -1,62 +0,0 @@ -'use client'; - -import MarketingForm from '@/components/pages/marketing/form/MarketingForm'; -import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; -import { MarketingApi } from '@/services/api/marketing/marketing'; -import { useRouter, useSearchParams } from 'next/navigation'; -import toast from 'react-hot-toast'; -import useSWR from 'swr'; - -const EditMarketingDelivery = () => { - const router = useRouter(); - const searchParams = useSearchParams(); - - const soId = searchParams.get('marketingId'); - - const { - data: marketing, - isLoading: isLoading, - mutate: refreshMarketing, - } = useSWR(`get-so-${soId}`, () => - MarketingApi.getSingle(soId ? parseInt(soId) : 0) - ); - - if (!soId) { - router.back(); - - return ( -
- -
- ); - } - - if (!isLoading && (!marketing || isResponseError(marketing))) { - router.replace('/404'); - return; - } - - if ( - isResponseSuccess(marketing) && - marketing.data.latest_approval.step_number != 3 - ) { - toast.error('Data Marketing perlu dilakukan approval terlebih dahulu!'); - router.back(); - } - - return ( -
- {isLoading && } - {!isLoading && isResponseSuccess(marketing) && ( - { - refreshMarketing(); - }} - /> - )} -
- ); -}; -export default EditMarketingDelivery; diff --git a/src/app/marketing/detail/layout.tsx b/src/app/marketing/detail/layout.tsx deleted file mode 100644 index 7220dfa1..00000000 --- a/src/app/marketing/detail/layout.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import SuspenseHelper from '@/components/helper/SuspenseHelper'; - -const Layout = ({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) => { - return {children}; -}; - -export default Layout; diff --git a/src/app/marketing/detail/page.tsx b/src/app/marketing/detail/page.tsx deleted file mode 100644 index 902251e8..00000000 --- a/src/app/marketing/detail/page.tsx +++ /dev/null @@ -1,49 +0,0 @@ -'use client'; - -import MarketingDetail from '@/components/pages/marketing/detail/MarketingDetail'; -import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; -import { MarketingApi } from '@/services/api/marketing/marketing'; -import { useRouter, useSearchParams } from 'next/navigation'; -import useSWR from 'swr'; - -const DetailMarketing = () => { - const router = useRouter(); - const searchParams = useSearchParams(); - - const soId = searchParams.get('marketingId'); - - const { - data: marketing, - isLoading: isLoading, - mutate: refreshMarketing, - } = useSWR(soId, (id: number) => MarketingApi.getSingle(id)); - - if (!soId) { - router.back(); - - return ( -
- -
- ); - } - - if (!isLoading && (!marketing || isResponseError(marketing))) { - router.replace('/404'); - return; - } - - return ( -
- {isLoading && } - {!isLoading && isResponseSuccess(marketing) && ( - - )} -
- ); -}; - -export default DetailMarketing; diff --git a/src/app/marketing/detail/sales-orders/edit/layout.tsx b/src/app/marketing/detail/sales-orders/edit/layout.tsx deleted file mode 100644 index 7220dfa1..00000000 --- a/src/app/marketing/detail/sales-orders/edit/layout.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import SuspenseHelper from '@/components/helper/SuspenseHelper'; - -const Layout = ({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) => { - return {children}; -}; - -export default Layout; diff --git a/src/app/marketing/detail/sales-orders/edit/page.tsx b/src/app/marketing/detail/sales-orders/edit/page.tsx deleted file mode 100644 index 19a098c5..00000000 --- a/src/app/marketing/detail/sales-orders/edit/page.tsx +++ /dev/null @@ -1,52 +0,0 @@ -'use client'; - -import MarketingForm from '@/components/pages/marketing/form/MarketingForm'; -import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; -import { MarketingApi } from '@/services/api/marketing/marketing'; -import { useRouter, useSearchParams } from 'next/navigation'; -import useSWR from 'swr'; - -const EditSalesOrder = () => { - const router = useRouter(); - const searchParams = useSearchParams(); - - const soId = searchParams.get('marketingId'); - - const { - data: marketing, - isLoading: isLoading, - mutate: refreshMarketing, - } = useSWR(`get-so-${soId}`, () => - MarketingApi.getSingle(soId ? parseInt(soId) : 0) - ); - - if (!soId) { - router.back(); - - return ( -
- -
- ); - } - - if (!isLoading && (!marketing || isResponseError(marketing))) { - router.replace('/404'); - return; - } - return ( -
- {isLoading && } - {!isLoading && isResponseSuccess(marketing) && ( - { - refreshMarketing(); - }} - /> - )} -
- ); -}; -export default EditSalesOrder; diff --git a/src/app/marketing/page.tsx b/src/app/marketing/page.tsx index c30ee501..d8b4bdcf 100644 --- a/src/app/marketing/page.tsx +++ b/src/app/marketing/page.tsx @@ -1,9 +1,14 @@ +import DeliveryOrderFormModal from '@/components/pages/marketing/DeliveryOrderFormModal'; import MarketingTable from '@/components/pages/marketing/MarketingTable'; +import SalesOrderFormModal from '@/components/pages/marketing/SalesOrderFormModal'; const Marketing = () => { return ( -
+
+ + +
); }; diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx new file mode 100644 index 00000000..b2b82a77 --- /dev/null +++ b/src/app/not-found.tsx @@ -0,0 +1,5 @@ +import PageNotFound from '@/components/helper/NotFoundPage'; + +export default function NotFound() { + return ; +} diff --git a/src/app/production/project-flock/detail/page.tsx b/src/app/production/project-flock/detail/page.tsx index 29a078dd..6187898e 100644 --- a/src/app/production/project-flock/detail/page.tsx +++ b/src/app/production/project-flock/detail/page.tsx @@ -50,5 +50,3 @@ const ProjectFlockDetailPage = () => { }; export default ProjectFlockDetailPage; -ProjectFlockDetail; -ProjectFlockDetail; diff --git a/src/components/MainDrawer.tsx b/src/components/MainDrawer.tsx index fdb65c38..71da0789 100644 --- a/src/components/MainDrawer.tsx +++ b/src/components/MainDrawer.tsx @@ -74,6 +74,8 @@ const MainDrawer = ({ const formattedPathname = pathname.endsWith('/') ? pathname : `${pathname}/`; + const isPathnameNotFoundPage = formattedPathname === '/404/'; + const isPermitted = ROUTE_PERMISSIONS[formattedPathname]?.some((permission) => permissionCheck(permission) ); @@ -82,10 +84,14 @@ const MainDrawer = ({ setMainDrawerOpen(!mainDrawerOpen); }; - if (!isPermitted) { + if (!isPermitted && !isPathnameNotFoundPage) { return ; } + if (isPathnameNotFoundPage) { + return children; + } + return ( { + return ( +
+

Halaman Tidak Ditemukan

+

+ Halaman atau data yang anda cari tidak ditemukan. +

+ +
+ ); +}; + +export default PageNotFound; diff --git a/src/components/helper/StatusBadge.tsx b/src/components/helper/StatusBadge.tsx index f9725fff..c90ddaee 100644 --- a/src/components/helper/StatusBadge.tsx +++ b/src/components/helper/StatusBadge.tsx @@ -28,6 +28,7 @@ const StatusBadge = ({ 'bg-error/20': color === 'error', 'bg-primary/20': color === 'info', 'bg-[#FF9A20]/12': color === 'warning', + 'bg-[#1166EF]/12': color === 'primary', }, className?.badge ), @@ -45,6 +46,7 @@ const StatusBadge = ({ 'text-error': color === 'error', 'text-primary': color === 'info', 'text-[#FF9A20]': color === 'warning', + 'text-[#1166EF]': color === 'primary', })} > diff --git a/src/components/helper/form/FormErrors.tsx b/src/components/helper/form/FormErrors.tsx index 1fd7b58f..60ec1687 100644 --- a/src/components/helper/form/FormErrors.tsx +++ b/src/components/helper/form/FormErrors.tsx @@ -1,5 +1,6 @@ import Alert from '@/components/Alert'; import Button from '@/components/Button'; +import { cn } from '@/lib/helper'; import { Icon } from '@iconify/react'; import { useState } from 'react'; @@ -10,34 +11,68 @@ import { useState } from 'react'; */ const AlertErrorList = ({ formErrorList, + className, onClose, + title, }: { formErrorList: string[]; + className?: { + alert?: string; + button?: string; + headerWrapper?: string; + headerIcon?: string; + headerText?: string; + titleWrapper?: string; + ul?: string; + li?: string; + }; onClose: () => void; + title?: string; }) => { if (formErrorList.length === 0) return null; return ( - -
-
- - - Terdapat {formErrorList.length} error pada form: + +
+
+ + + {title || `Terdapat ${formErrorList.length} error pada form:`}
-
    +
      {formErrorList.map((error, index) => ( -
    • +
    • {error}
    • ))} diff --git a/src/components/input/DebouncedTextArea.tsx b/src/components/input/DebouncedTextArea.tsx index 3df2c032..24d4b4e7 100644 --- a/src/components/input/DebouncedTextArea.tsx +++ b/src/components/input/DebouncedTextArea.tsx @@ -7,6 +7,7 @@ import TextArea, { TextAreaProps } from '@/components/input/TextArea'; interface DebouncedTextAreaProps extends TextAreaProps { delay?: number; + ref?: React.RefObject; } const DebouncedTextArea = (props: DebouncedTextAreaProps) => { @@ -19,6 +20,11 @@ const DebouncedTextArea = (props: DebouncedTextAreaProps) => { const [debouncedChangeEvent] = useDebounce(internalChangeEvent, delay ?? 300); const [debouncedValue] = useDebounce(internalValue, delay ?? 300); + // Sync internal value with external props.value when it changes (e.g., form reset) + useEffect(() => { + setInternalValue(props.value); + }, [props.value]); + const internalChangeHandler: ChangeEventHandler = ( e ) => { @@ -35,6 +41,7 @@ const DebouncedTextArea = (props: DebouncedTextAreaProps) => { return (