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(
baseClassNames.drawerSidebarContent,
'w-full min-w-120 sm:w-fit'
'w-full sm:min-w-120 sm:w-fit'
),
};
} else if (variant === 'left') {
@@ -76,7 +76,7 @@ const Drawer = ({
),
drawerSidebarContent: cn(
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';
import { ReactNode, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import useSWRImmutable from 'swr/immutable';
import useSWR from 'swr';
import { useAuth } from '@/services/hooks/useAuth';
import { httpClientFetcher, SWRHttpKey } from '@/services/http/client';
import { isResponseSuccess } from '@/lib/api-helper';
import { GetMeResponse } from '@/types/api/api-general';
// TODO: delete this later, DONT HARDCODE USER DATA
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',
},
},
],
},
],
};
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import { BaseApiResponse, GetMeResponse } from '@/types/api/api-general';
import { AxiosError } from 'axios';
import { redirectToSSO } from '@/lib/auth-helper';
interface RequireAuthProps {
children?: ReactNode;
}
const RequireAuth = ({ children }: RequireAuthProps) => {
const router = useRouter();
const { setUser, setIsLoadingUser } = useAuth();
const { user, setUser, setIsLoadingUser } = useAuth();
const { data: userResponse, isLoading: isLoadingUserResponse } =
useSWRImmutable<GetMeResponse & { ok?: boolean }, unknown, SWRHttpKey>(
'/auth/sso/userinfo',
httpClientFetcher,
{
shouldRetryOnError: false,
revalidateOnFocus: false,
revalidateOnReconnect: false,
refreshInterval: 0,
}
);
const {
data: userResponse,
isLoading: isLoadingUserResponse,
error: userErrorResponse,
} = useSWR<
GetMeResponse & { ok?: boolean },
AxiosError<BaseApiResponse>,
SWRHttpKey
>('/sso/userinfo', httpClientFetcher, {
shouldRetryOnError: false,
useEffect(() => {
setIsLoadingUser(isLoadingUserResponse);
}, [isLoadingUserResponse, setIsLoadingUser]);
// refresh every 13 minutes
refreshInterval: 13 * 60 * 1000,
});
useEffect(() => {
if (isResponseSuccess(userResponse)) {
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
// if (isLoadingUserResponse && !userResponse) {
// return (
// <div className='w-full flex flex-row justify-center items-center p-4'>
// <span className='loading loading-spinner loading-xl' />
// </div>
// );
// }
// Explicitly handle 401 redirect from the component level
useEffect(() => {
if (
isResponseError(userResponse) &&
userErrorResponse?.response?.status === 401
) {
// 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;
@@ -305,6 +305,7 @@ const MarketingTable = () => {
value={pageSize}
onChange={pageSizeChangeHandler}
options={ROWS_OPTIONS}
className='flex sm:flex-row flex-col gap-3 items-end justify-end'
>
{/* select multiple product */}
<SelectInput
@@ -575,7 +575,7 @@ const MarketingForm = ({
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
label='Pelanggan'
options={customerOptions}
@@ -650,7 +650,7 @@ const MarketingForm = ({
)}
{/* Input Notes */}
<div className='grid grid-cols-2 gap-3'>
<div className='grid sm:grid-cols-2 gap-3'>
<DebouncedTextArea
required
name='notes'
@@ -193,7 +193,7 @@ const DeliveryOrderProductForm = ({
</div>
)}
<div className='grid grid-cols-2 gap-4'>
<div className='grid sm:grid-cols-2 gap-4'>
<SelectInput
options={options}
label='Produk'
@@ -183,7 +183,7 @@ const SalesOrderProductForm = ({
{/* <small className='block text-rose-500'>
{JSON.stringify(formik.errors)}
</small> */}
<div className='grid grid-cols-2 gap-4 z-200'>
<div className='grid sm:grid-cols-2 gap-4 z-200'>
<PatternInput
name='vehicle_number'
label='No. Polisi'
@@ -1,7 +1,6 @@
'use client';
import Button from '@/components/Button';
import Card from '@/components/Card';
import { FormHeader } from '@/components/helper/form/FormHeader';
import NumberInput from '@/components/input/NumberInput';
import SelectInput, { OptionType } from '@/components/input/SelectInput';
@@ -283,7 +283,7 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
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='w-full flex flex-col justify-between items-end gap-2'>
<div className='flex flex-col sm:flex-row gap-3 w-full'>
@@ -1,4 +1,5 @@
import SelectInput from '@/components/input/SelectInput';
import { cn } from '@/lib/helper';
export interface OptionType {
label: string;
@@ -10,6 +11,7 @@ interface TableRowSizeSelectorProps {
onChange: (val: OptionType | OptionType[] | null) => void;
options: OptionType[];
children?: React.ReactNode;
className?: string;
}
export const TableRowSizeSelector = ({
@@ -17,9 +19,10 @@ export const TableRowSizeSelector = ({
onChange,
options,
children,
className,
}: TableRowSizeSelectorProps) => {
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}
<SelectInput
label='Baris'
@@ -338,4 +338,4 @@
}
]
}
]
]