Skip to main content

Layout dan Routing

Layout

Kita akan membuat layout sederhana dengan menggunakan komponen-komponen dari alurkerja-ui.

Layout kita akan terdiri dari:

  • satu sidebar
  • satu header
  • satu area konten

Contoh layout bisa dilihat pada src/feature/Layout.tsx. Pada contoh kode di bawah ini juga ada penggunaan RoleContext.Provider yang akan kita buat untuk mengatur otorisasi.

import { Header, Sidebar } from "alurkerja-ui";
import { useState } from "react";
import { Outlet } from "react-router-dom";
import { Role, RoleContext } from "../context/RoleContext";
import { hrdMenuConfig, pegawaiMenuConfig } from "../menuConfig";

const storageRole = localStorage.getItem("role") || "Pegawai";

export function Layout() {
const [role, setRole] = useState<Role>(storageRole as Role);
const [toggled, setToggled] = useState(false);

const menuConfig = role === "Pegawai" ? pegawaiMenuConfig : hrdMenuConfig;

function handleClickAvatar() {
const newRole = role === "Pegawai" ? "HRD" : "Pegawai";

localStorage.setItem("role", newRole);
setRole(newRole);
}

return (
<RoleContext.Provider value={role as Role}>
<div className="flex">
<Sidebar
menuConfig={menuConfig}
toggled={toggled}
setToggled={setToggled}
/>
<div className="flex-grow bg-slate-50 min-h-full">
<Header role={role} onClickAvatar={handleClickAvatar} />
<main className="p-4">
<Outlet />
</main>
</div>
</div>
</RoleContext.Provider>
);
}

Tambahkan src/menuConfig.ts untuk konfigurasi sidebar.

import { MenuConfig } from "alurkerja-ui";

export const pegawaiMenuConfig: MenuConfig[] = [
{
label: "Beranda",
href: "/",
},
{
label: "Pengajuan Cuti",
href: "/cuti",
},
];

export const hrdMenuConfig: MenuConfig[] = [
{
label: "Beranda",
href: "/",
},
];

Pada komponen Layout ini, kita juga membuat fungsi otorisasi bohongan yang sederhana pada header untuk keperluan demo. Otorisasi ini kita buat menggunakan context dan local storage. Detail fungsi otorisasi ini bisa dilihat:

  • pada src/context/RoleContext.tsx untuk context
import { createContext } from "react";

export type Role = "Pegawai" | "HRD";
export const RoleContext = createContext<Role>("Pegawai");
  • pada src/App.tsx untuk penggunaan context. Catatan: contoh kode berikut memiliki kode mengenai rute yang akan berjalan setelah bagian Rute di tahap ini.
import { AuthContext, ThemeContext, themeConfig } from "alurkerja-ui";
import { axiosInstance } from "./lib/axios";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { routes } from "./routes";

const router = createBrowserRouter(routes);

function App() {
return (
<AuthContext.Provider value={axiosInstance}>
<ThemeContext.Provider value={themeConfig}>
<RouterProvider router={router} />
</ThemeContext.Provider>
</AuthContext.Provider>
);
}

export default App;
  • pada src/feature/RoleGate.tsx untuk komponen otorisasi. Harap diingat ini hanya otorisasi bohongan untuk keperluan demo.
import { useContext } from "react";
import { Role, RoleContext } from "../context/RoleContext";

interface RoleGateProps {
allowed: Role;
children: React.ReactNode;
}
export function RoleGate({ allowed, children }: RoleGateProps) {
const role = useContext(RoleContext);

if (role !== allowed) {
return <div>Dilarang Masuk</div>;
}

return <>{children}</>;
}

Rute

Di Javan, untuk mengendalikan rute, kita biasanya menggunakan react-router-dom.

npm install react-router-dom

Setelah menginstal react-router-dom, buat daftar rute pada src/routes.tsx. Pada contoh kode berikut, terdapat juga CutiCreate yang akan kita buat.

import { RouteObject } from "react-router-dom";
import { CutiTable } from "./feature/CutiTable";
import { CutiCreate } from "./feature/CutiCreate";
import { RoleGate } from "./feature/RoleGate";
import { Layout } from "./feature/Layout";

export const routes: RouteObject[] = [
{
path: "/",
element: <Layout />,
errorElement: <div>404</div>,
children: [
{
index: true,
element: <div>Selamat Datang</div>,
},
{
path: "cuti",
children: [
{
index: true,
element: (
<RoleGate allowed="Pegawai">
<CutiTable />
</RoleGate>
),
},
{
path: "create",
element: (
<RoleGate allowed="Pegawai">
<CutiCreate />
</RoleGate>
),
},
],
},
],
},
];

Kemudian, gunakan rute tersebut pada src/App.tsx. Jika mengikuti kode pada bagian Layout tadi, maka kode berikut seharusnya tidak ada perubahan dengan contoh kode sebelumnya.

import { AuthContext, ThemeContext, themeConfig } from "alurkerja-ui";
import { axiosInstance } from "./lib/axios";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { routes } from "./routes";

const router = createBrowserRouter(routes);

function App() {
return (
<AuthContext.Provider value={axiosInstance}>
<ThemeContext.Provider value={themeConfig}>
<RouterProvider router={router} />
</ThemeContext.Provider>
</AuthContext.Provider>
);
}

export default App;
  • pada src/feature/RoleGate.tsx untuk komponen otorisasi
import { useContext } from "react";
import { Role, RoleContext } from "../context/RoleContext";

interface RoleGateProps {
allowed: Role;
children: React.ReactNode;
}
export function RoleGate({ allowed, children }: RoleGateProps) {
const role = useContext(RoleContext);

if (role !== allowed) {
return <div>Dilarang Masuk</div>;
}

return <>{children}</>;
}

Di sini kita juga sekalian membuat komponen sederhana pada berkas src/feature/CutiCreate.tsx. Komponen sederhana ini kita buat untuk melihat apakah kode tabel yang kita buat, mampu berfungsi untuk mengarahkan kita ke halaman lain, dan halaman tersebut muncul dengan benar.

export function CutiCreate() {
return <div>Tambah Cuti</div>;
}

Pastikan aplikasi bekerja dengan benar

Jika aplikasi berjalan dengan benar:

  • kita bisa memilih menu pada sidebar untuk berpindah halaman,
  • berpindah halaman dengan menekan tombol "Tambah" pada tabel cuti,
  • berganti role ketika menekan avatar pada header,
  • role tertentu hanya mampu mengakses halaman yang diizinkan, sesuai pada konfigurasi rute.