fix(FE): fix page responsive in project flock dan marketing modules

This commit is contained in:
randy-ar
2025-12-27 16:36:07 +07:00
parent d49bca1d40
commit c44e63bd2b
10 changed files with 79 additions and 183 deletions
+2 -2
View File
@@ -64,7 +64,7 @@ const Drawer = ({
), ),
drawerSidebarContent: cn( drawerSidebarContent: cn(
baseClassNames.drawerSidebarContent, baseClassNames.drawerSidebarContent,
'w-full min-w-120 sm:w-fit' 'w-full sm:min-w-120 sm:w-fit'
), ),
}; };
} else if (variant === 'left') { } else if (variant === 'left') {
@@ -76,7 +76,7 @@ const Drawer = ({
), ),
drawerSidebarContent: cn( drawerSidebarContent: cn(
baseClassNames.drawerSidebarContent, baseClassNames.drawerSidebarContent,
'w-full min-w-120 sm:w-fit' 'w-full sm:min-w-120 sm:w-fit'
), ),
}; };
} }
+66 -173
View File
@@ -1,197 +1,90 @@
'use client'; 'use client';
import { ReactNode, useEffect } from 'react'; import { ReactNode, useEffect } from 'react';
import { useRouter } from 'next/navigation'; import useSWR from 'swr';
import useSWRImmutable from 'swr/immutable';
import { useAuth } from '@/services/hooks/useAuth'; import { useAuth } from '@/services/hooks/useAuth';
import { httpClientFetcher, SWRHttpKey } from '@/services/http/client'; import { httpClientFetcher, SWRHttpKey } from '@/services/http/client';
import { isResponseSuccess } from '@/lib/api-helper'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { GetMeResponse } from '@/types/api/api-general'; import { BaseApiResponse, GetMeResponse } from '@/types/api/api-general';
import { AxiosError } from 'axios';
// TODO: delete this later, DONT HARDCODE USER DATA import { redirectToSSO } from '@/lib/auth-helper';
const DUMMY_USER = {
id: 1,
email: 'admin@mbugroup.id',
npk: '0001',
name: 'Super Admin',
image: null,
created_at: '2025-09-30T03:24:20.899229Z',
updated_at: '2025-09-30T03:24:20.899229Z',
roles: [
{
id: 1,
key: 'mbu.super_admin',
name: 'MBU Administrator',
client: {
id: 1,
name: 'PT Mitra Berlian Unggas',
alias: 'MBU',
},
permissions: [
{
id: 1,
name: 'mbu:purchase:read',
action: 'read',
client: {
id: 1,
name: 'PT Mitra Berlian Unggas',
alias: 'MBU',
},
},
{
id: 2,
name: 'mbu:purchase:create',
action: 'create',
client: {
id: 1,
name: 'PT Mitra Berlian Unggas',
alias: 'MBU',
},
},
{
id: 3,
name: 'mbu:purchase:approve',
action: 'approve',
client: {
id: 1,
name: 'PT Mitra Berlian Unggas',
alias: 'MBU',
},
},
],
},
{
id: 2,
key: 'lti.super_admin',
name: 'LTI Administrator',
client: {
id: 2,
name: 'PT Lumbung Telur Indonesia',
alias: 'LTI',
},
permissions: [
{
id: 4,
name: 'lti:purchase:read',
action: 'read',
client: {
id: 2,
name: 'PT Lumbung Telur Indonesia',
alias: 'LTI',
},
},
{
id: 5,
name: 'lti:purchase:create',
action: 'create',
client: {
id: 2,
name: 'PT Lumbung Telur Indonesia',
alias: 'LTI',
},
},
{
id: 6,
name: 'lti:purchase:approve',
action: 'approve',
client: {
id: 2,
name: 'PT Lumbung Telur Indonesia',
alias: 'LTI',
},
},
],
},
{
id: 3,
key: 'manbu.super_admin',
name: 'MANBU Administrator',
client: {
id: 3,
name: 'PT Mandiri Berlian Unggas',
alias: 'MANBU',
},
permissions: [
{
id: 7,
name: 'manbu:purchase:read',
action: 'read',
client: {
id: 3,
name: 'PT Mandiri Berlian Unggas',
alias: 'MANBU',
},
},
{
id: 8,
name: 'manbu:purchase:create',
action: 'create',
client: {
id: 3,
name: 'PT Mandiri Berlian Unggas',
alias: 'MANBU',
},
},
{
id: 9,
name: 'manbu:purchase:approve',
action: 'approve',
client: {
id: 3,
name: 'PT Mandiri Berlian Unggas',
alias: 'MANBU',
},
},
],
},
],
};
interface RequireAuthProps { interface RequireAuthProps {
children?: ReactNode; children?: ReactNode;
} }
const RequireAuth = ({ children }: RequireAuthProps) => { const RequireAuth = ({ children }: RequireAuthProps) => {
const router = useRouter(); const { user, setUser, setIsLoadingUser } = useAuth();
const { setUser, setIsLoadingUser } = useAuth();
const { data: userResponse, isLoading: isLoadingUserResponse } = const {
useSWRImmutable<GetMeResponse & { ok?: boolean }, unknown, SWRHttpKey>( data: userResponse,
'/auth/sso/userinfo', isLoading: isLoadingUserResponse,
httpClientFetcher, error: userErrorResponse,
{ } = useSWR<
shouldRetryOnError: false, GetMeResponse & { ok?: boolean },
revalidateOnFocus: false, AxiosError<BaseApiResponse>,
revalidateOnReconnect: false, SWRHttpKey
refreshInterval: 0, >('/sso/userinfo', httpClientFetcher, {
} shouldRetryOnError: false,
);
useEffect(() => { // refresh every 13 minutes
setIsLoadingUser(isLoadingUserResponse); refreshInterval: 13 * 60 * 1000,
}, [isLoadingUserResponse, setIsLoadingUser]); });
useEffect(() => { useEffect(() => {
if (isResponseSuccess(userResponse)) { if (isResponseSuccess(userResponse)) {
setUser(userResponse.data); setUser(userResponse.data);
} else {
// router.replace(process.env.NEXT_PUBLIC_SSO_LOGIN_URL as string);
// TODO: remove this later, DONT HARDCODE USER DATA
setUser(DUMMY_USER);
} }
}, [userResponse, setIsLoadingUser, setUser]); }, [userResponse, setUser]);
// TODO: uncomment this later // Explicitly handle 401 redirect from the component level
// if (isLoadingUserResponse && !userResponse) { useEffect(() => {
// return ( if (
// <div className='w-full flex flex-row justify-center items-center p-4'> isResponseError(userResponse) &&
// <span className='loading loading-spinner loading-xl' /> userErrorResponse?.response?.status === 401
// </div> ) {
// ); // Clear cache to prevent stale data from rendering children
// } // mutate('/sso/userinfo', undefined, { revalidate: false }); // Optional: if using global mutate
setUser(undefined);
redirectToSSO();
}
}, [userErrorResponse, setUser, userResponse]);
return <>{children}</>; useEffect(() => {
setIsLoadingUser(isLoadingUserResponse);
}, [isLoadingUserResponse]);
if (
(isLoadingUserResponse && !userResponse && !userErrorResponse) ||
(!userResponse && !userErrorResponse)
) {
return (
<div className='w-full flex flex-row justify-center items-center p-4'>
<span className='loading loading-spinner loading-xl' />
</div>
);
}
if (userErrorResponse) {
return (
<div className='w-full h-screen flex flex-col justify-center items-center gap-4'>
<h2 className='text-2xl font-bold text-error'>Authentication Failed</h2>
<p className='text-gray-600'>
Please try refreshing the page or contact support if the problem
persists.
</p>
<button
className='btn btn-primary'
onClick={() => window.location.reload()}
>
Retry
</button>
</div>
);
}
return <>{isResponseSuccess(userResponse) && user && children}</>;
}; };
export default RequireAuth; export default RequireAuth;
@@ -305,6 +305,7 @@ const MarketingTable = () => {
value={pageSize} value={pageSize}
onChange={pageSizeChangeHandler} onChange={pageSizeChangeHandler}
options={ROWS_OPTIONS} options={ROWS_OPTIONS}
className='flex sm:flex-row flex-col gap-3 items-end justify-end'
> >
{/* select multiple product */} {/* select multiple product */}
<SelectInput <SelectInput
@@ -575,7 +575,7 @@ const MarketingForm = ({
wrapper: 'bg-white w-full', wrapper: 'bg-white w-full',
}} }}
> >
<div className='grid grid-cols-2 gap-3 mt-3'> <div className='grid sm:grid-cols-2 gap-3 mt-3'>
<SelectInput <SelectInput
label='Pelanggan' label='Pelanggan'
options={customerOptions} options={customerOptions}
@@ -650,7 +650,7 @@ const MarketingForm = ({
)} )}
{/* Input Notes */} {/* Input Notes */}
<div className='grid grid-cols-2 gap-3'> <div className='grid sm:grid-cols-2 gap-3'>
<DebouncedTextArea <DebouncedTextArea
required required
name='notes' name='notes'
@@ -193,7 +193,7 @@ const DeliveryOrderProductForm = ({
</div> </div>
)} )}
<div className='grid grid-cols-2 gap-4'> <div className='grid sm:grid-cols-2 gap-4'>
<SelectInput <SelectInput
options={options} options={options}
label='Produk' label='Produk'
@@ -183,7 +183,7 @@ const SalesOrderProductForm = ({
{/* <small className='block text-rose-500'> {/* <small className='block text-rose-500'>
{JSON.stringify(formik.errors)} {JSON.stringify(formik.errors)}
</small> */} </small> */}
<div className='grid grid-cols-2 gap-4 z-200'> <div className='grid sm:grid-cols-2 gap-4 z-200'>
<PatternInput <PatternInput
name='vehicle_number' name='vehicle_number'
label='No. Polisi' label='No. Polisi'
@@ -1,7 +1,6 @@
'use client'; 'use client';
import Button from '@/components/Button'; import Button from '@/components/Button';
import Card from '@/components/Card';
import { FormHeader } from '@/components/helper/form/FormHeader'; import { FormHeader } from '@/components/helper/form/FormHeader';
import NumberInput from '@/components/input/NumberInput'; import NumberInput from '@/components/input/NumberInput';
import SelectInput, { OptionType } from '@/components/input/SelectInput'; import SelectInput, { OptionType } from '@/components/input/SelectInput';
@@ -283,7 +283,7 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
return ( return (
<> <>
<div className='min-h-screen w-full p-0 sm:p-4'> <div className='min-h-screen w-full p-4'>
<div className='flex flex-col gap-2 mb-4'> <div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col justify-between items-end gap-2'> <div className='w-full flex flex-col justify-between items-end gap-2'>
<div className='flex flex-col sm:flex-row gap-3 w-full'> <div className='flex flex-col sm:flex-row gap-3 w-full'>
@@ -1,4 +1,5 @@
import SelectInput from '@/components/input/SelectInput'; import SelectInput from '@/components/input/SelectInput';
import { cn } from '@/lib/helper';
export interface OptionType { export interface OptionType {
label: string; label: string;
@@ -10,6 +11,7 @@ interface TableRowSizeSelectorProps {
onChange: (val: OptionType | OptionType[] | null) => void; onChange: (val: OptionType | OptionType[] | null) => void;
options: OptionType[]; options: OptionType[];
children?: React.ReactNode; children?: React.ReactNode;
className?: string;
} }
export const TableRowSizeSelector = ({ export const TableRowSizeSelector = ({
@@ -17,9 +19,10 @@ export const TableRowSizeSelector = ({
onChange, onChange,
options, options,
children, children,
className,
}: TableRowSizeSelectorProps) => { }: TableRowSizeSelectorProps) => {
return ( return (
<div className='flex flex-row gap-3 items-end justify-end'> <div className={cn('flex flex-row gap-3 items-end justify-end', className)}>
{children} {children}
<SelectInput <SelectInput
label='Baris' label='Baris'
@@ -338,4 +338,4 @@
} }
] ]
} }
] ]