diff --git a/src/app/percobaan/_lib/ClientRouter.txt b/src/app/percobaan/_lib/ClientRouter.txt deleted file mode 100644 index b666bba3..00000000 --- a/src/app/percobaan/_lib/ClientRouter.txt +++ /dev/null @@ -1,300 +0,0 @@ -"use client"; -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-empty-object-type */ -import { z } from "zod"; - -type RouterLeaf> = { - get: () => string; - query: (params: z.infer) => string; - parse: (searchParams: URLSearchParams) => z.infer; -}; - -// Helper type to convert dashes to camelCase -type DashToCamelCase = S extends `${infer F}-${infer R}` - ? `${F}${Capitalize>}` - : S; - -// Modified RouterPath to handle dash conversion -type RouterPath< - T extends z.ZodType = z.ZodObject<{}>, - Segments extends string[] = [] -> = Segments extends [infer Head extends string, ...infer Tail extends string[]] - ? { [K in DashToCamelCase]: RouterPath } - : RouterLeaf; - -type RemoveLeadingSlash = S extends `/${infer Rest}` - ? Rest - : S; - -type SplitPath = S extends `${infer Head}/${infer Tail}` - ? [Head, ...SplitPath] - : S extends "" - ? [] - : [S]; - -type WibuRouterOptions = { - prefix?: string; - name?: string; -}; - -export class V2ClientRouter { - private tree: any = {}; - private prefix: string = ""; - private name: string = ""; - private querySchemas: Map = new Map(); - - constructor(options?: WibuRouterOptions) { - if (options?.prefix) { - // Ensure prefix starts with / and doesn't end with / - this.prefix = options.prefix.startsWith("/") - ? options.prefix - : `/${options.prefix}`; - - if (this.prefix.endsWith("/")) { - this.prefix = this.prefix.slice(0, -1); - } - } - - if (options?.name) { - this.name = options.name; - } - } - - // Convert dash-case to camelCase - private toCamelCase(str: string): string { - return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase()); - } - - add< - Path extends string, - NormalizedPath extends string = RemoveLeadingSlash, - Segments extends string[] = SplitPath, - T extends z.ZodType = z.ZodObject<{}> - >( - path: Path, - schema?: { query: T } - ): V2ClientRouter< - Routes & - (NormalizedPath extends "" - ? RouterLeaf - : { - [K in Segments[0] as DashToCamelCase]: RouterPath< - T, - Segments extends [any, ...infer Rest] ? Rest : [] - >; - }) - > { - const normalizedPath = path.startsWith("/") ? path : `/${path}`; - const fullPath = `${this.prefix}${normalizedPath}`; - const segments = normalizedPath.split("/").filter(Boolean); - - // Store the Zod schema for this path - if (schema) { - this.querySchemas.set(fullPath, schema.query); - } else { - // Default empty schema - this.querySchemas.set(fullPath, z.object({})); - } - - const handleQuery = (params: any): string => { - if (!params || Object.keys(params).length === 0) return fullPath; - - // Validate params against schema - const schema = this.querySchemas.get(fullPath); - if (schema) { - try { - schema.parse(params); - } catch (error) { - console.error("Query params validation failed:", error); - throw new Error("Invalid query parameters"); - } - } - - const queryString = Object.entries(params) - .map( - ([key, value]) => - `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}` - ) - .join("&"); - return `${fullPath}?${queryString}`; - }; - - const handleGet = () => fullPath; - - const handleParse = (searchParams: URLSearchParams): any => { - const schema = this.querySchemas.get(fullPath); - if (!schema) return {}; - - // Convert URLSearchParams to object - const queryObject: Record = {}; - searchParams.forEach((value, key) => { - queryObject[key] = value; - }); - - // Parse through Zod schema - try { - return schema.parse(queryObject); - } catch (error) { - console.error("Failed to parse search params:", error); - // Return safe default values - const safeParsed = schema.safeParse(queryObject); - if (safeParsed.success) { - return safeParsed.data; - } - return {}; - } - }; - - // Special case for root path "/" - if (segments.length === 0) { - this.tree.get = handleGet; - this.tree.query = handleQuery; - this.tree.parse = handleParse; - } else { - let current = this.tree; - for (const segment of segments) { - // Use camelCase version for the property name - const camelSegment = this.toCamelCase(segment); - if (!current[camelSegment]) { - current[camelSegment] = {}; - } - current = current[camelSegment]; - } - - current.get = handleGet; - current.query = handleQuery; - current.parse = handleParse; - } - - return this as any; - } - - // Add a method to incorporate another router's routes into this one - use( - name: N, - childRouter: V2ClientRouter - ): V2ClientRouter, ChildRoutes>> { - const camelName = this.toCamelCase(name); - - if (!this.tree[camelName]) { - this.tree[camelName] = {}; - } - - // Copy query schemas from child router - childRouter.querySchemas.forEach((schema, path) => { - const newPath = `${this.prefix}/${name}${path.substring( - childRouter.prefix.length - )}`; - this.querySchemas.set(newPath, schema); - }); - - // Create a deep copy of the child router's tree with updated paths - const updatePaths = (obj: any, childPrefix: string): any => { - const result: any = {}; - - for (const key in obj) { - if (key === "get" && typeof obj[key] === "function") { - // Capture the original path from the child router - const originalPath = obj[key](); - // Create a new function that returns the combined path - result[key] = () => { - const newPath = `${this.prefix}/${name}${originalPath.substring( - childPrefix.length - )}`; - return newPath; - }; - } else if (key === "query" && typeof obj[key] === "function") { - // Capture the child router's prefix for path adjustment - result[key] = (params: any) => { - // Get the original result without query params - const originalPathWithoutParams = obj["get"](); - // Create the proper path with our parent prefix - const newBasePath = `${ - this.prefix - }/${name}${originalPathWithoutParams.substring( - childPrefix.length - )}`; - - // Add query params if any - if (!params || Object.keys(params).length === 0) return newBasePath; - - // Validate params against schema - const newPath = `${ - this.prefix - }/${name}${originalPathWithoutParams.substring( - childPrefix.length - )}`; - const schema = this.querySchemas.get(newPath); - - if (schema) { - try { - schema.parse(params); - } catch (error) { - console.error("Query params validation failed:", error); - throw new Error("Invalid query parameters"); - } - } - - const queryString = Object.entries(params) - .map( - ([k, v]) => - `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}` - ) - .join("&"); - return `${newBasePath}?${queryString}`; - }; - } else if (key === "parse" && typeof obj[key] === "function") { - result[key] = (searchParams: URLSearchParams) => { - const originalPath = obj["get"](); - const newPath = `${this.prefix}/${name}${originalPath.substring( - childPrefix.length - )}`; - const schema = this.querySchemas.get(newPath); - - if (!schema) return {}; - - // Convert URLSearchParams to object - const queryObject: Record = {}; - searchParams.forEach((value, key) => { - queryObject[key] = value; - }); - - // Parse through Zod schema - try { - return schema.parse(queryObject); - } catch (error) { - console.error("Failed to parse search params:", error); - // Return safe default values - const safeParsed = schema.safeParse(queryObject); - if (safeParsed.success) { - return safeParsed.data; - } - return {}; - } - }; - } else if (typeof obj[key] === "object" && obj[key] !== null) { - result[key] = updatePaths(obj[key], childPrefix); - } else { - result[key] = obj[key]; - } - } - - return result; - }; - - // Copy the child router's tree into this router - this.tree[camelName] = updatePaths( - (childRouter as any).tree, - childRouter.prefix - ); - - return this as any; - } - - // Allow access to the tree with strong typing - get routes(): Routes { - return this.tree as Routes; - } -} - -export default V2ClientRouter; \ No newline at end of file diff --git a/src/app/percobaan/_router/router.txt b/src/app/percobaan/_router/router.txt deleted file mode 100644 index e394a306..00000000 --- a/src/app/percobaan/_router/router.txt +++ /dev/null @@ -1,20 +0,0 @@ -import { z } from "zod"; -import V2ClientRouter from "../_lib/ClientRouter"; - -const dashboard = new V2ClientRouter({ - prefix: "/dashboard", - name: "dashboard", -}) - .add("/", { - query: z.object({ - page: z.string(), - }), - }) - .add("/berita"); - -const router = new V2ClientRouter({ - prefix: "/percobaan", - name: "percobaan", -}).use("dashboard", dashboard); - -export default router; diff --git a/src/app/percobaan/dashboard/berita/page.txt b/src/app/percobaan/dashboard/berita/page.txt deleted file mode 100644 index 4bba2a3f..00000000 --- a/src/app/percobaan/dashboard/berita/page.txt +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -function Page() { - return ( -
- berita -
- ); -} - -export default Page; diff --git a/src/app/percobaan/dashboard/page.txt b/src/app/percobaan/dashboard/page.txt deleted file mode 100644 index cc00a4fd..00000000 --- a/src/app/percobaan/dashboard/page.txt +++ /dev/null @@ -1,33 +0,0 @@ -'use client' -import { useSearchParams } from 'next/navigation'; -import router from '../_router/router'; -import { Box } from '@mantine/core'; - - -function Page() { - const { page } = router.routes.dashboard.parse(useSearchParams()) - switch (page) { - case "1": - return - case "2": - return - case "3": - return - default: - return - } -} - -const Page1 = () => { - return Page 1 -} - -const Page2 = () => { - return Page 2 -} - -const Page3 = () => { - return Page 3 -} - -export default Page; diff --git a/src/app/percobaan/page.txt b/src/app/percobaan/page.txt deleted file mode 100644 index e74f0edd..00000000 --- a/src/app/percobaan/page.txt +++ /dev/null @@ -1,105 +0,0 @@ -'use client' -import { Box, Container, Flex, Grid, SimpleGrid, Skeleton, Stack, Text, Title } from '@mantine/core'; -import { useSearchParams } from 'next/navigation'; -import React from 'react'; - -const tx = ` -Untuk menambahkan fitur berbagi nomor WhatsApp di kode yang Anda miliki, saya akan menjelaskan beberapa pendekatan yang bisa digunakan. Biasanya ini dilakukan dengan membuat link yang ketika diklik akan membuka aplikasi WhatsApp dengan nomor tujuan yang sudah diatur. -Berikut adalah cara mengimplementasikannya pada kode React Anda: -` - -function Page() { - return ( - - - - 1 - - - 1 - - - - {Array.from({ length: 10 }).map((_, i) => ( - 1 - ))} - - - 1 - - {tx} - {tx} - apa kabar - - - - - - - ); -} - -export default Page; - -const Halaman = [Halaman1, Halaman2, Halaman3] - -function Page2() { - const page = useSearchParams().get("p"); - if (!page) return - - halo 1 - {Array.from({ length: 4 }).map((v, k) => )} - - - - - return ( - - - halo 2 - {Halaman[Number(page)-1]()} - - - - ); -} - - - -function Halaman1() { - return - ini halaman 1 - -} - - -function Halaman2() { - return - ini halaman 2 - -} - - -function Halaman3() { - return - ini halaman 3 - -} - diff --git a/src/app/percobaan/page2.txt b/src/app/percobaan/page2.txt deleted file mode 100644 index 69f2114b..00000000 --- a/src/app/percobaan/page2.txt +++ /dev/null @@ -1,18 +0,0 @@ -'use client' -import { Button, Group, Stack } from "@mantine/core" -import { Link } from "next-view-transitions" -import router from "./_router/router" - -const Page = () => { - return - - {[1, 2, 3].map((v) => ())} - - - - -} - -export default Page \ No newline at end of file