diff --git a/src/components/search/SearchBox.tsx b/src/components/search/SearchBox.tsx index c9fb0b0..f6cba1e 100644 --- a/src/components/search/SearchBox.tsx +++ b/src/components/search/SearchBox.tsx @@ -1,5 +1,5 @@ import { Loader, X } from "lucide-react"; -import { useRef, useTransition } from "react"; +import { useRef } from "react"; import { Input } from "@/components/ui/input"; interface SearchBoxProps { @@ -16,7 +16,6 @@ export function SearchBox({ keyword, inputProps, }: SearchBoxProps) { - const [, startTransition] = useTransition(); const inputRef = useRef(null); return (
@@ -27,9 +26,9 @@ export function SearchBox({ className="w-full bg-base-200/30" value={keyword} onChange={(e) => { - startTransition(() => { - setKeyword(e.target.value); - }); + setKeyword(e.target.value); + // startTransition(() => { + // }); }} {...inputProps} /> diff --git a/src/components/wrappers/ListPageHeader.tsx b/src/components/wrappers/ListPageHeader.tsx index 741d468..4760938 100644 --- a/src/components/wrappers/ListPageHeader.tsx +++ b/src/components/wrappers/ListPageHeader.tsx @@ -1,12 +1,15 @@ +import { twMerge } from "tailwind-merge"; + interface ListPageHeaderProps { title: string; formTrigger?:React.ReactNode; searchBox?:React.ReactNode; +containerClassname?:string; } -export function ListPageHeader({title,formTrigger,searchBox}:ListPageHeaderProps){ +export function ListPageHeader({title,formTrigger,searchBox,containerClassname}:ListPageHeaderProps){ return ( -
+

{title}

diff --git a/src/hooks/use-page-searchquery.ts b/src/hooks/use-page-searchquery.ts index 03ea8f8..dd5bfef 100644 --- a/src/hooks/use-page-searchquery.ts +++ b/src/hooks/use-page-searchquery.ts @@ -29,7 +29,8 @@ export function usePageSearchQuery(path: ValidRoutes) { }); } - }, [debouncedValue, navigate, sq,page]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [debouncedValue, navigate, page]); function updatePage(page: number) { startTransition(() => { navigate({ diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 90efafc..5e3f6fe 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -14,9 +14,11 @@ import { Route as rootRoute } from './routes/__root' import { Route as DashboardLayoutImport } from './routes/dashboard/layout' import { Route as IndexImport } from './routes/index' import { Route as ProfileIndexImport } from './routes/profile/index' +import { Route as MoneyIndexImport } from './routes/money/index' import { Route as DashboardIndexImport } from './routes/dashboard/index' import { Route as AuthIndexImport } from './routes/auth/index' import { Route as AuthSignupImport } from './routes/auth/signup' +import { Route as MoneyMoneyIndexImport } from './routes/money/$money/index' import { Route as DashboardTeamsIndexImport } from './routes/dashboard/teams/index' import { Route as DashboardProjectsIndexImport } from './routes/dashboard/projects/index' import { Route as DashboardOsProjectsIndexImport } from './routes/dashboard/os-projects/index' @@ -46,6 +48,12 @@ const ProfileIndexRoute = ProfileIndexImport.update({ getParentRoute: () => rootRoute, } as any) +const MoneyIndexRoute = MoneyIndexImport.update({ + id: '/money/', + path: '/money/', + getParentRoute: () => rootRoute, +} as any) + const DashboardIndexRoute = DashboardIndexImport.update({ id: '/', path: '/', @@ -64,6 +72,12 @@ const AuthSignupRoute = AuthSignupImport.update({ getParentRoute: () => rootRoute, } as any) +const MoneyMoneyIndexRoute = MoneyMoneyIndexImport.update({ + id: '/money/$money/', + path: '/money/$money/', + getParentRoute: () => rootRoute, +} as any) + const DashboardTeamsIndexRoute = DashboardTeamsIndexImport.update({ id: '/teams/', path: '/teams/', @@ -153,6 +167,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof DashboardIndexImport parentRoute: typeof DashboardLayoutImport } + '/money/': { + id: '/money/' + path: '/money' + fullPath: '/money' + preLoaderRoute: typeof MoneyIndexImport + parentRoute: typeof rootRoute + } '/profile/': { id: '/profile/' path: '/profile' @@ -216,6 +237,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof DashboardTeamsIndexImport parentRoute: typeof DashboardLayoutImport } + '/money/$money/': { + id: '/money/$money/' + path: '/money/$money' + fullPath: '/money/$money' + preLoaderRoute: typeof MoneyMoneyIndexImport + parentRoute: typeof rootRoute + } } } @@ -255,6 +283,7 @@ export interface FileRoutesByFullPath { '/auth/signup': typeof AuthSignupRoute '/auth': typeof AuthIndexRoute '/dashboard/': typeof DashboardIndexRoute + '/money': typeof MoneyIndexRoute '/profile': typeof ProfileIndexRoute '/dashboard/challenges': typeof DashboardChallengesIndexRoute '/dashboard/hackathons': typeof DashboardHackathonsIndexRoute @@ -264,6 +293,7 @@ export interface FileRoutesByFullPath { '/dashboard/os-projects': typeof DashboardOsProjectsIndexRoute '/dashboard/projects': typeof DashboardProjectsIndexRoute '/dashboard/teams': typeof DashboardTeamsIndexRoute + '/money/$money': typeof MoneyMoneyIndexRoute } export interface FileRoutesByTo { @@ -271,6 +301,7 @@ export interface FileRoutesByTo { '/auth/signup': typeof AuthSignupRoute '/auth': typeof AuthIndexRoute '/dashboard': typeof DashboardIndexRoute + '/money': typeof MoneyIndexRoute '/profile': typeof ProfileIndexRoute '/dashboard/challenges': typeof DashboardChallengesIndexRoute '/dashboard/hackathons': typeof DashboardHackathonsIndexRoute @@ -280,6 +311,7 @@ export interface FileRoutesByTo { '/dashboard/os-projects': typeof DashboardOsProjectsIndexRoute '/dashboard/projects': typeof DashboardProjectsIndexRoute '/dashboard/teams': typeof DashboardTeamsIndexRoute + '/money/$money': typeof MoneyMoneyIndexRoute } export interface FileRoutesById { @@ -289,6 +321,7 @@ export interface FileRoutesById { '/auth/signup': typeof AuthSignupRoute '/auth/': typeof AuthIndexRoute '/dashboard/': typeof DashboardIndexRoute + '/money/': typeof MoneyIndexRoute '/profile/': typeof ProfileIndexRoute '/dashboard/challenges/': typeof DashboardChallengesIndexRoute '/dashboard/hackathons/': typeof DashboardHackathonsIndexRoute @@ -298,6 +331,7 @@ export interface FileRoutesById { '/dashboard/os-projects/': typeof DashboardOsProjectsIndexRoute '/dashboard/projects/': typeof DashboardProjectsIndexRoute '/dashboard/teams/': typeof DashboardTeamsIndexRoute + '/money/$money/': typeof MoneyMoneyIndexRoute } export interface FileRouteTypes { @@ -308,6 +342,7 @@ export interface FileRouteTypes { | '/auth/signup' | '/auth' | '/dashboard/' + | '/money' | '/profile' | '/dashboard/challenges' | '/dashboard/hackathons' @@ -317,12 +352,14 @@ export interface FileRouteTypes { | '/dashboard/os-projects' | '/dashboard/projects' | '/dashboard/teams' + | '/money/$money' fileRoutesByTo: FileRoutesByTo to: | '/' | '/auth/signup' | '/auth' | '/dashboard' + | '/money' | '/profile' | '/dashboard/challenges' | '/dashboard/hackathons' @@ -332,6 +369,7 @@ export interface FileRouteTypes { | '/dashboard/os-projects' | '/dashboard/projects' | '/dashboard/teams' + | '/money/$money' id: | '__root__' | '/' @@ -339,6 +377,7 @@ export interface FileRouteTypes { | '/auth/signup' | '/auth/' | '/dashboard/' + | '/money/' | '/profile/' | '/dashboard/challenges/' | '/dashboard/hackathons/' @@ -348,6 +387,7 @@ export interface FileRouteTypes { | '/dashboard/os-projects/' | '/dashboard/projects/' | '/dashboard/teams/' + | '/money/$money/' fileRoutesById: FileRoutesById } @@ -356,7 +396,9 @@ export interface RootRouteChildren { DashboardLayoutRoute: typeof DashboardLayoutRouteWithChildren AuthSignupRoute: typeof AuthSignupRoute AuthIndexRoute: typeof AuthIndexRoute + MoneyIndexRoute: typeof MoneyIndexRoute ProfileIndexRoute: typeof ProfileIndexRoute + MoneyMoneyIndexRoute: typeof MoneyMoneyIndexRoute } const rootRouteChildren: RootRouteChildren = { @@ -364,7 +406,9 @@ const rootRouteChildren: RootRouteChildren = { DashboardLayoutRoute: DashboardLayoutRouteWithChildren, AuthSignupRoute: AuthSignupRoute, AuthIndexRoute: AuthIndexRoute, + MoneyIndexRoute: MoneyIndexRoute, ProfileIndexRoute: ProfileIndexRoute, + MoneyMoneyIndexRoute: MoneyMoneyIndexRoute, } export const routeTree = rootRoute @@ -381,7 +425,9 @@ export const routeTree = rootRoute "/dashboard", "/auth/signup", "/auth/", - "/profile/" + "/money/", + "/profile/", + "/money/$money/" ] }, "/": { @@ -411,6 +457,9 @@ export const routeTree = rootRoute "filePath": "dashboard/index.tsx", "parent": "/dashboard" }, + "/money/": { + "filePath": "money/index.tsx" + }, "/profile/": { "filePath": "profile/index.tsx" }, @@ -445,6 +494,9 @@ export const routeTree = rootRoute "/dashboard/teams/": { "filePath": "dashboard/teams/index.tsx", "parent": "/dashboard" + }, + "/money/$money/": { + "filePath": "money/$money/index.tsx" } } } diff --git a/src/routes/money/$money/index.tsx b/src/routes/money/$money/index.tsx new file mode 100644 index 0000000..b620155 --- /dev/null +++ b/src/routes/money/$money/index.tsx @@ -0,0 +1,9 @@ + +import { createFileRoute } from '@tanstack/react-router' +import { OneMoneyPage } from '@/routes/money/-components/onemoney/OneMoneyPage' + +export const Route = createFileRoute('/money/$money/')({ + component: OneMoneyPage +}) + + \ No newline at end of file diff --git a/src/routes/money/-components/MoneyPage.tsx b/src/routes/money/-components/MoneyPage.tsx new file mode 100644 index 0000000..7e21097 --- /dev/null +++ b/src/routes/money/-components/MoneyPage.tsx @@ -0,0 +1,43 @@ + +import { SearchBox } from "@/components/search/SearchBox"; +import { Suspense } from "react"; +import { ListPageHeader } from "@/components/wrappers/ListPageHeader"; +import { Helmet } from "@/components/wrappers/custom-helmet"; +import { usePageSearchQuery } from "@/hooks/use-page-searchquery"; +import { CardsListSuspenseFallback } from "@/components/loaders/GenericDataCardsListSuspenseFallback"; +import { CreateMoneyForm } from "./form/create"; +import { MoneyList } from "./list/MoneyList"; + +interface MoneyPageProps { +} + +export function MoneyPage({}: MoneyPageProps) { + const { debouncedValue, isDebouncing, keyword, setKeyword } = + usePageSearchQuery("/money"); + return ( +
+ + } + searchBox={ + + } + /> + +
+ }> + + +
+
+ ); +} diff --git a/src/routes/money/-components/form/base.tsx b/src/routes/money/-components/form/base.tsx new file mode 100644 index 0000000..3ac864c --- /dev/null +++ b/src/routes/money/-components/form/base.tsx @@ -0,0 +1,20 @@ + + +import { UseMutationResult } from "@tanstack/react-query"; + +interface BaseMoneyFormProps> { + mutation: UseMutationResult; + row: T; + afterSave?: () => void; +} +export function BaseMoneyForm>( + {}: BaseMoneyFormProps, +) { + return ( +
+

BaseMoneyForm

+
+ ); +} + + \ No newline at end of file diff --git a/src/routes/money/-components/form/create.tsx b/src/routes/money/-components/form/create.tsx new file mode 100644 index 0000000..5e0df8c --- /dev/null +++ b/src/routes/money/-components/form/create.tsx @@ -0,0 +1,61 @@ + + +import { useState } from "react"; +import { DiaDrawer } from "@/components/wrappers/DiaDrawer"; +import { Plus } from "lucide-react"; +import { makeHotToast } from "@/components/toasters"; +import { BaseMoneyForm } from "./base"; +import { useMutation } from "@tanstack/react-query"; + +export function CreateMoneyForm() { + const [open, setOpen] = useState(false); + + const mutation = useMutation({ + mutationFn: (value: {}) => { + return new Promise<{}>((resolve) => { + setTimeout(() => { + resolve(value); + }, 2000); + }); + }, + onSuccess: () => { + makeHotToast({ + title: "Money added", + description: "Money has been added successfully", + variant: "success", + }); + setOpen(false); + }, + onError(error) { + makeHotToast({ + title: "Something went wrong", + description: error.message, + variant: "error", + }); + }, + meta: { + invalidates: ["money"], + }, + }); + return ( + + + Add new + + } + > +
+ +
+
+ ); +} + + + \ No newline at end of file diff --git a/src/routes/money/-components/form/update.tsx b/src/routes/money/-components/form/update.tsx new file mode 100644 index 0000000..152ac65 --- /dev/null +++ b/src/routes/money/-components/form/update.tsx @@ -0,0 +1,58 @@ + + +import { useState } from "react"; +import { DiaDrawer } from "@/components/wrappers/DiaDrawer"; +import { Edit } from "lucide-react"; +import { makeHotToast } from "@/components/toasters"; +import { BaseMoneyForm } from "./base"; +import { useMutation } from "@tanstack/react-query"; + +interface UpdateMoneyformInterface { + item: Record & { id: string }; +} +export function UpdateMoneyform({ item }: UpdateMoneyformInterface) { + const [open, setOpen] = useState(false); + const mutation = useMutation({ + mutationFn: (value: {}) => { + return new Promise<{}>((resolve) => { + setTimeout(() => { + resolve(value); + }, 2000); + }); + }, + onSuccess: () => { + makeHotToast({ + title: "Money added", + description: "Money has been added successfully", + variant: "success", + }); + setOpen(false); + }, + onError(error) { + makeHotToast({ + title: "Something went wrong", + description: error.message, + variant: "error", + }); + }, + meta: { + invalidates: ["money"], + }, + }); + return ( + } + > +
+ +
+
+ ); +} + + + \ No newline at end of file diff --git a/src/routes/money/-components/list/MoneyList.tsx b/src/routes/money/-components/list/MoneyList.tsx new file mode 100644 index 0000000..b3451ac --- /dev/null +++ b/src/routes/money/-components/list/MoneyList.tsx @@ -0,0 +1,76 @@ + +import { ItemNotFound } from "@/components/wrappers/ItemNotFound"; +import { ErrorWrapper } from "@/components/wrappers/ErrorWrapper"; +import { useSuspenseQuery } from "@tanstack/react-query"; +import { Link } from "@tanstack/react-router"; +import ResponsivePagination from "react-responsive-pagination"; +import { usePageSearchQuery } from "@/hooks/use-page-searchquery"; +import { UpdateMoneyform } from "@/routes/money/-components/form/update"; +import { moneyListQueryOptions } from "@/routes/money/-query-options/money-query-option"; + +interface MoneyListProps { + keyword?: string; +} + +export function MoneyList({ keyword = "" }: MoneyListProps) { + const { page,updatePage } = usePageSearchQuery("/money"); + const query = useSuspenseQuery(moneyListQueryOptions({ keyword,page })); + const data = query.data; + const error = query.error; + + if (error) { + return ( +
+ +
+ ); + } + if (!data || data.items.length === 0) { + return ( +
+ +
+ ); + } + return ( +
+
    + {data.items.map((item) => { + return ( +
  • +
    +
    +

    + {item.id} +

    + +
    + +
    see details
    + ➡️ + +
    +
  • + ); + })} +
+
+ { + updatePage(e); + }} + /> +
+
+ ); +} + + diff --git a/src/routes/money/-components/onemoney/OneMoneyDetails.tsx b/src/routes/money/-components/onemoney/OneMoneyDetails.tsx new file mode 100644 index 0000000..1957e06 --- /dev/null +++ b/src/routes/money/-components/onemoney/OneMoneyDetails.tsx @@ -0,0 +1,32 @@ + +import { useSuspenseQuery } from "@tanstack/react-query"; +import { useParams } from "@tanstack/react-router"; +import { oneMoneyQueryOptions } from "@/routes/money/-query-options/money-query-option"; +import { ErrorWrapper } from "@/components/wrappers/ErrorWrapper"; + +interface OneMoneyDetailsProps { +} + +export function OneMoneyDetails({}: OneMoneyDetailsProps) { + const { money } = useParams({ from: "/money/$money/" }); + const query = useSuspenseQuery(oneMoneyQueryOptions({ money })); + const data = query.data; + const error = query.error; + + if (error) { + return ( +
+ +
+ ); + } + return ( +
+
+ {JSON.stringify(data, null, 2)} +
+
+ ); +} + + \ No newline at end of file diff --git a/src/routes/money/-components/onemoney/OneMoneyPage.tsx b/src/routes/money/-components/onemoney/OneMoneyPage.tsx new file mode 100644 index 0000000..5341d9f --- /dev/null +++ b/src/routes/money/-components/onemoney/OneMoneyPage.tsx @@ -0,0 +1,24 @@ + +import { Suspense } from "react"; +import { OneMoneyDetails } from "./OneMoneyDetails"; + +interface OneMoneyPageProps { +} + +export function OneMoneyPage({}: OneMoneyPageProps) { + return ( +
+ +
Loading
+
+ } + > + + +
+ ); +} + + \ No newline at end of file diff --git a/src/routes/money/-query-options/money-query-option.ts b/src/routes/money/-query-options/money-query-option.ts new file mode 100644 index 0000000..53a6e2f --- /dev/null +++ b/src/routes/money/-query-options/money-query-option.ts @@ -0,0 +1,55 @@ + +import { queryOptions } from "@tanstack/react-query"; + + +interface moneyQueryOptionPropss { + keyword: string; + page?: number; +} +export function moneyListQueryOptions({ keyword, page=1 }: moneyQueryOptionPropss) { + return queryOptions({ + queryKey: ["money_list", keyword,page], + queryFn: () => { + return new Promise<{ + page: number; + perPage: number; + totaleItems: number; + totalPages: number; + items: Array & { id: string }>; + }>((res) => { + setTimeout(() => { + const resArray = Array.from({ length: 30 }, (_, i) => ({ + id: "money_id_"+i, + })); + res({ + page, + perPage: 10, + totaleItems: 30, + totalPages: 3, + items: resArray + .slice((page - 1) * 10, page * 10) + .filter((item) =>item.id.includes(keyword)) + }); + }, 1000); + }); + }, + }); +} +interface oneMoneyQueryOptionPropss { + money: string; +} +export function oneMoneyQueryOptions({ money }: oneMoneyQueryOptionPropss) { + return queryOptions({ + queryKey: ["one_money", money], + queryFn: () => { + return new Promise<{ id: string }>((res) => { + setTimeout(() => { + res({ + id: money, + }); + }, 1000); + }); + }, + }); +} + \ No newline at end of file diff --git a/src/routes/money/index.tsx b/src/routes/money/index.tsx new file mode 100644 index 0000000..ce4d33a --- /dev/null +++ b/src/routes/money/index.tsx @@ -0,0 +1,15 @@ + +import { createFileRoute } from "@tanstack/react-router"; +import { z } from "zod"; +import { MoneyPage } from "@/routes/money/-components/MoneyPage"; + +const searchparams = z.object({ + page: z.number().optional(), + sq: z.string().optional(), +}); + +export const Route = createFileRoute("/money/")({ + validateSearch: (search) => searchparams.parse(search), + component:MoneyPage +}); + diff --git a/src/scripts/scafold-pages/base-templates.ts b/src/scripts/scafold-pages/base-templates.ts index 16d8c8c..08000a0 100644 --- a/src/scripts/scafold-pages/base-templates.ts +++ b/src/scripts/scafold-pages/base-templates.ts @@ -43,7 +43,7 @@ export function ${capitalpagename}Page({}: ${capitalpagename}PageProps) { const { debouncedValue, isDebouncing, keyword, setKeyword } = usePageSearchQuery("/${path}"); return ( -
+
-
+
}> <${capitalpagename}List keyword={keyword} /> @@ -111,24 +111,29 @@ export function ${capitalpagename}List({ keyword = "" }: ${capitalpagename}ListP ); } return ( -
-
    +
    +
      {data.items.map((item) => { return (
    • -
      - {item.id} +
      +
      +

      + {item.id} +

      + +
      - see details +
      see details
      + ➡️
      -
    • ); })} diff --git a/src/scripts/scafold-pages/one-page-template.ts b/src/scripts/scafold-pages/one-page-template.ts index ffb527c..a370663 100644 --- a/src/scripts/scafold-pages/one-page-template.ts +++ b/src/scripts/scafold-pages/one-page-template.ts @@ -28,7 +28,7 @@ interface One${capitalpagename}PageProps { export function One${capitalpagename}Page({}: One${capitalpagename}PageProps) { return ( -
      +
      @@ -73,9 +73,11 @@ export function One${capitalpagename}Details({}: One${capitalpagename}DetailsPro ); } return ( -
      +
      +
      {JSON.stringify(data, null, 2)}
      +
      ); } diff --git a/src/scripts/scafold-pages/query-options-tempaltes.ts b/src/scripts/scafold-pages/query-options-tempaltes.ts index 99f480c..8654628 100644 --- a/src/scripts/scafold-pages/query-options-tempaltes.ts +++ b/src/scripts/scafold-pages/query-options-tempaltes.ts @@ -14,7 +14,7 @@ interface ${pagename}QueryOptionPropss { } export function ${pagename}ListQueryOptions({ keyword, page=1 }: ${pagename}QueryOptionPropss) { return queryOptions({ - queryKey: ["${pagename}_list", keyword], + queryKey: ["${pagename}_list", keyword,page], queryFn: () => { return new Promise<{ page: number; @@ -24,12 +24,17 @@ export function ${pagename}ListQueryOptions({ keyword, page=1 }: ${pagename}Quer items: Array & { id: string }>; }>((res) => { setTimeout(() => { + const resArray = Array.from({ length: 30 }, (_, i) => ({ + id: "${pagename}_id_"+i, + })); res({ page, perPage: 10, totaleItems: 30, totalPages: 3, - items: [{ id: "id_1" }, { id: "id_2" }, { id: "id_3" }], + items: resArray + .slice((page - 1) * 10, page * 10) + .filter((item) =>item.id.includes(keyword)) }); }, 1000); });