mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
fix(FE): resolve merge conflict
This commit is contained in:
@@ -1,186 +1,46 @@
|
||||
'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 { data: userResponse, isLoading: isLoadingUserResponse } =
|
||||
useSWRImmutable<GetMeResponse & { ok?: boolean }, unknown, SWRHttpKey>(
|
||||
'/auth/sso/userinfo',
|
||||
httpClientFetcher,
|
||||
{
|
||||
shouldRetryOnError: false,
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: false,
|
||||
refreshInterval: 0,
|
||||
}
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoadingUser(isLoadingUserResponse);
|
||||
}, [isLoadingUserResponse, setIsLoadingUser]);
|
||||
const {
|
||||
data: userResponse,
|
||||
isLoading: isLoadingUserResponse,
|
||||
error: userErrorResponse,
|
||||
} = useSWR<
|
||||
GetMeResponse & { ok?: boolean },
|
||||
AxiosError<BaseApiResponse>,
|
||||
SWRHttpKey
|
||||
>('/sso/userinfo', httpClientFetcher, {
|
||||
shouldRetryOnError: false,
|
||||
});
|
||||
|
||||
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]);
|
||||
|
||||
// Explicitly handle 401 redirect from the component level
|
||||
useEffect(() => {
|
||||
if (userErrorResponse?.response?.status === 401) {
|
||||
redirectToSSO();
|
||||
}
|
||||
}, [userErrorResponse]);
|
||||
|
||||
// TODO: uncomment this later
|
||||
// if (isLoadingUserResponse && !userResponse) {
|
||||
@@ -191,7 +51,25 @@ const RequireAuth = ({ children }: RequireAuthProps) => {
|
||||
// );
|
||||
// }
|
||||
|
||||
return <>{children}</>;
|
||||
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) && children}</>;
|
||||
};
|
||||
|
||||
export default RequireAuth;
|
||||
|
||||
@@ -7,17 +7,26 @@ import Button from '@/components/Button';
|
||||
import Tabs from '@/components/Tabs';
|
||||
import ClosingGeneralInformationTable from '@/components/pages/closing/ClosingGeneralInformationTable';
|
||||
|
||||
import { ClosingGeneralInformation } from '@/types/api/closing';
|
||||
import {
|
||||
ClosingGeneralInformation,
|
||||
BaseClosingSales,
|
||||
} from '@/types/api/closing';
|
||||
import ClosingSapronakTabContent from './ClosingSapronakTabContent';
|
||||
import ClosingSapronakCalculationTabContent from '@/components/pages/closing/ClosingSapronakCalculationTabContent';
|
||||
import ClosingOverheadTabContent from '@/components/pages/closing/ClosingOverheadTabContent';
|
||||
import SalesReportTable from './sale/SalesReportTable';
|
||||
|
||||
interface ClosingDetailProps {
|
||||
id: number;
|
||||
initialValue?: ClosingGeneralInformation;
|
||||
salesData?: BaseClosingSales;
|
||||
}
|
||||
|
||||
const ClosingDetail: React.FC<ClosingDetailProps> = ({ id, initialValue }) => {
|
||||
const ClosingDetail: React.FC<ClosingDetailProps> = ({
|
||||
id,
|
||||
initialValue,
|
||||
salesData,
|
||||
}) => {
|
||||
const [activeTab, setActiveTab] = useState<string>('sapronak');
|
||||
|
||||
const closingDetailTabs = useMemo(() => {
|
||||
@@ -35,7 +44,7 @@ const ClosingDetail: React.FC<ClosingDetailProps> = ({ id, initialValue }) => {
|
||||
{
|
||||
id: 'penjualan',
|
||||
label: 'Penjualan',
|
||||
content: 'Penjualan',
|
||||
content: <SalesReportTable initialValues={salesData} />,
|
||||
},
|
||||
{
|
||||
id: 'overhead',
|
||||
|
||||
@@ -263,7 +263,7 @@ const SalesReportTable = ({
|
||||
tableWrapperClassName: 'overflow-x-auto',
|
||||
tableClassName: 'w-full table-auto text-sm',
|
||||
headerColumnClassName:
|
||||
'px-4 py-3 text-xs font-semibold text-gray-500 last:flex last:flex-row last:justify-end whitespace-nowrap border-l border-l-gray-200 border-r border-r-gray-200 border-t border-t-gray-200 border-gray-200 border-b-0',
|
||||
'px-4 py-3 text-xs font-semibold text-gray-500 whitespace-nowrap border-l border-l-gray-200 border-r border-r-gray-200 border-t border-t-gray-200 border-gray-200 border-b-0',
|
||||
bodyRowClassName:
|
||||
'hover:bg-gray-50 transition-colors border-b border-gray-200 first:border-t first:border-t-gray-200 border-l border-l-gray-200 border-r border-r-gray-200',
|
||||
bodyColumnClassName:
|
||||
|
||||
Reference in New Issue
Block a user