diff --git a/src/components/dropdown/README.md b/src/components/dropdown/README.md
deleted file mode 100644
index e682682a..00000000
--- a/src/components/dropdown/README.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# Dropdown Component
-
-Komponen Dropdown reusable berdasarkan DaisyUI yang mengatasi issue children component yang ter-render sebelum dropdown dibuka.
-
-## Features
-
-- ✅ **Conditional Rendering**: Children hanya di-render ketika dropdown aktif/terbuka
-- ✅ **Click Outside to Close**: Otomatis menutup dropdown ketika klik di luar area dropdown
-- ✅ **Multiple Positions**: Support berbagai posisi (top, bottom, left, right) dengan alignment (start, center, end)
-- ✅ **Hover Support**: Optional hover mode untuk membuka dropdown
-- ✅ **Customizable**: Mendukung custom className untuk container dan content
-
-## Usage
-
-### Basic Example
-
-```tsx
-import Dropdown from '@/components/dropdown/Dropdown';
-import Menu from '@/components/menu/Menu';
-import MenuItem from '@/components/menu/MenuItem';
-
-Click Me
- }
->
-
-
-```
-
-### With Position
-
-```tsx
-Dropdown}
- contentClassName="w-52 mt-3"
->
- {/* Your content */}
-
-```
-
-### Hover Mode
-
-```tsx
-Hover Me}
->
- {/* Your content */}
-
-```
-
-## Props
-
-| Prop | Type | Default | Description |
-|------|------|---------|-------------|
-| `trigger` | `ReactNode` | - | **Required**. Element yang akan men-trigger dropdown |
-| `children` | `ReactNode` | - | **Required**. Content dropdown yang akan ditampilkan |
-| `position` | `'top' \| 'bottom' \| 'left' \| 'right' \| 'top-start' \| 'top-end' \| 'bottom-start' \| 'bottom-end' \| 'left-start' \| 'left-end' \| 'right-start' \| 'right-end'` | `'bottom'` | Posisi dropdown relatif terhadap trigger |
-| `align` | `'start' \| 'center' \| 'end'` | `'start'` | Alignment dropdown (digunakan jika position tidak mengandung alignment) |
-| `hover` | `boolean` | `false` | Aktifkan mode hover untuk membuka dropdown |
-| `className` | `string` | - | Custom className untuk container dropdown |
-| `contentClassName` | `string` | - | Custom className untuk content dropdown |
-
-## Position Examples
-
-- `bottom` - Dropdown muncul di bawah, align ke start
-- `bottom-end` - Dropdown muncul di bawah, align ke end
-- `bottom-center` - Dropdown muncul di bawah, align ke center
-- `top-start` - Dropdown muncul di atas, align ke start
-- `left-end` - Dropdown muncul di kiri, align ke end
-- Dan seterusnya...
-
-## Key Benefits
-
-1. **Performance**: Children tidak di-render sampai dropdown dibuka, menghemat resources
-2. **Clean State**: Setiap kali dropdown dibuka, children di-render fresh
-3. **DaisyUI Compatible**: Menggunakan class DaisyUI yang sudah ada
-4. **Accessible**: Menggunakan proper ARIA attributes dan keyboard navigation
diff --git a/src/components/helper/RequireAuth.tsx b/src/components/helper/RequireAuth.tsx
index dbd4b6bc..119d74cb 100644
--- a/src/components/helper/RequireAuth.tsx
+++ b/src/components/helper/RequireAuth.tsx
@@ -6,147 +6,9 @@ import useSWRImmutable from 'swr/immutable';
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';
interface RequireAuthProps {
children?: ReactNode;
@@ -156,17 +18,20 @@ const RequireAuth = ({ children }: RequireAuthProps) => {
const router = useRouter();
const { setUser, setIsLoadingUser } = useAuth();
- const { data: userResponse, isLoading: isLoadingUserResponse } =
- useSWRImmutable(
- '/auth/sso/userinfo',
- httpClientFetcher,
- {
- shouldRetryOnError: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshInterval: 0,
- }
- );
+ const {
+ data: userResponse,
+ isLoading: isLoadingUserResponse,
+ error: userErrorResponse,
+ } = useSWRImmutable<
+ GetMeResponse & { ok?: boolean },
+ AxiosError,
+ SWRHttpKey
+ >('/sso/userinfo', httpClientFetcher, {
+ shouldRetryOnError: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ refreshInterval: 0,
+ });
useEffect(() => {
setIsLoadingUser(isLoadingUserResponse);
@@ -175,23 +40,25 @@ const RequireAuth = ({ children }: RequireAuthProps) => {
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);
+ } else if (
+ isResponseError(userErrorResponse?.response?.data) &&
+ typeof window !== 'undefined'
+ ) {
+ router.replace(
+ `${process.env.NEXT_PUBLIC_SSO_LOGIN_URL as string}?redirect_url=${window.location.href}`
+ );
}
- }, [userResponse, setIsLoadingUser, setUser]);
+ }, [userResponse, userErrorResponse, setIsLoadingUser, setUser]);
- // TODO: uncomment this later
- // if (isLoadingUserResponse && !userResponse) {
- // return (
- //
- //
- //
- // );
- // }
+ if (isLoadingUserResponse && !userResponse && !userErrorResponse) {
+ return (
+
+
+
+ );
+ }
- return <>{children}>;
+ return <>{isResponseSuccess(userResponse) && children}>;
};
export default RequireAuth;