Просмотр исходного кода

feat: implement users api and hooks

Mohammad Mahdi Salimi 1 месяц назад
Родитель
Сommit
1251694556

+ 7 - 5
src/core/react-query/keys.ts

@@ -1,10 +1,12 @@
 export const queryKeys = {
 export const queryKeys = {
-  roles: {
-    all: ['roles'] as const,
-  },
-
   users: {
   users: {
     all: ['users'] as const,
     all: ['users'] as const,
-    // search: (username: string) => ['users', 'search', username] as const,
+
+    lists: () => [...queryKeys.users.all, 'list'] as const,
+    list: (params: unknown) => [...queryKeys.users.lists(), params] as const,
+
+    details: () => [...queryKeys.users.all, 'detail'] as const,
+    detail: (id: number | string) =>
+      [...queryKeys.users.details(), id] as const,
   },
   },
 }
 }

+ 1 - 1
src/features/auth/sign-in/components/user-auth-form.tsx

@@ -5,7 +5,7 @@ import { useNavigate } from '@tanstack/react-router'
 import { Loader2, LogIn } from 'lucide-react'
 import { Loader2, LogIn } from 'lucide-react'
 import { toast } from 'sonner'
 import { toast } from 'sonner'
 
 
-import { useLogin } from '@/hooks/useAuth'
+import { useLogin } from '@/hooks/auth/useAuth'
 import { cn } from '@/lib/utils'
 import { cn } from '@/lib/utils'
 import { Button } from '@/components/ui/button'
 import { Button } from '@/components/ui/button'
 import {
 import {

+ 0 - 4
src/features/users/api/getUsers.ts

@@ -1,4 +0,0 @@
-import { http } from '@/core/api/http'
-import { type GetUserResponse } from '../types'
-
-export const getUsers = () => http.get<GetUserResponse>('/admin/users')

+ 1 - 1
src/features/users/components/users-table.tsx

@@ -23,9 +23,9 @@ import {
 } from '@/components/ui/table'
 } from '@/components/ui/table'
 import { DataTablePagination, DataTableToolbar } from '@/components/data-table'
 import { DataTablePagination, DataTableToolbar } from '@/components/data-table'
 import { roles } from '../data/data'
 import { roles } from '../data/data'
-import { type User } from '../data/schema'
 import { DataTableBulkActions } from './data-table-bulk-actions'
 import { DataTableBulkActions } from './data-table-bulk-actions'
 import { usersColumns as columns } from './users-columns'
 import { usersColumns as columns } from './users-columns'
+import { type User } from '@/types/users.types'
 
 
 type DataTableProps = {
 type DataTableProps = {
   data: User[]
   data: User[]

+ 0 - 15
src/features/users/hooks/useUsers.tsx

@@ -1,15 +0,0 @@
-import { queryKeys } from '@/core/react-query/keys'
-import { useQuery } from '@tanstack/react-query'
-import { getUsers } from '../api/getUsers'
-
-export const useUsers = (enabled?: boolean) => {
-  return useQuery({
-    queryKey: queryKeys.users.all,
-    queryFn: async () => {
-      const res = await getUsers()
-      return res.data?.users
-    },
-    staleTime: 1000 * 60 * 2,
-    enabled,
-  })
-}

+ 3 - 2
src/features/users/index.tsx

@@ -9,7 +9,7 @@ import { UsersDialogs } from './components/users-dialogs'
 import { UsersPrimaryButtons } from './components/users-primary-buttons'
 import { UsersPrimaryButtons } from './components/users-primary-buttons'
 import { UsersProvider } from './components/users-provider'
 import { UsersProvider } from './components/users-provider'
 import { UsersTable } from './components/users-table'
 import { UsersTable } from './components/users-table'
-import { useUsers } from './hooks/useUsers'
+import { useUsers } from '../../hooks/users/useUsers'
 
 
 const route = getRouteApi('/_authenticated/users/')
 const route = getRouteApi('/_authenticated/users/')
 
 
@@ -17,7 +17,8 @@ export function Users() {
   const search = route.useSearch()
   const search = route.useSearch()
   const navigate = route.useNavigate()
   const navigate = route.useNavigate()
 
 
-  const { data: users } = useUsers()
+  const { data } = useUsers({ page: 1, per_page: 10 })
+  const users = data?.data.users
 
 
   return (
   return (
     <UsersProvider>
     <UsersProvider>

+ 0 - 1
src/features/users/types.ts

@@ -1 +0,0 @@
-export type GetUserResponse = any

+ 0 - 0
src/hooks/useAuth.tsx → src/hooks/auth/useAuth.tsx


+ 13 - 0
src/hooks/users/useUser.tsx

@@ -0,0 +1,13 @@
+// src/hooks/users/useUser.ts
+import { useQuery } from '@tanstack/react-query'
+import { usersService } from '@/services/users.service'
+import type { GetUserDetailResponse } from '@/types/users.types'
+import { queryKeys } from '@/core/react-query/keys'
+
+export function useUser(userId: number | string) {
+  return useQuery<GetUserDetailResponse>({
+    queryKey: queryKeys.users.detail(userId),
+    queryFn: () => usersService.detail(userId),
+    enabled: !!userId,
+  })
+}

+ 13 - 0
src/hooks/users/useUsers.tsx

@@ -0,0 +1,13 @@
+import { keepPreviousData, useQuery } from '@tanstack/react-query'
+import { usersService } from '@/services/users.service'
+import type { PaginationParams } from '@/types/common.types'
+import type { GetUserResponse } from '@/types/users.types'
+import { queryKeys } from '@/core/react-query/keys'
+
+export function useUsers(params: PaginationParams = { page: 1, per_page: 10 }) {
+  return useQuery<GetUserResponse>({
+    queryKey: queryKeys.users.list(params),
+    queryFn: () => usersService.list(params),
+    placeholderData: keepPreviousData,
+  })
+}

+ 1 - 1
src/main.tsx

@@ -53,7 +53,7 @@ const queryClient = new QueryClient({
       if (error instanceof AxiosError) {
       if (error instanceof AxiosError) {
         if (error.response?.status === 401) {
         if (error.response?.status === 401) {
           toast.error('Session expired!')
           toast.error('Session expired!')
-          useAuthStore.getState().auth.reset()
+          useAuthStore.getState().logout()
           const redirect = `${router.history.location.href}`
           const redirect = `${router.history.location.href}`
           router.navigate({ to: '/sign-in', search: { redirect } })
           router.navigate({ to: '/sign-in', search: { redirect } })
         }
         }

+ 26 - 0
src/services/users.service.ts

@@ -0,0 +1,26 @@
+import http from '@/core/api/http'
+import type {
+  GetUserResponse,
+  GetUserDetailResponse,
+} from '@/types/users.types'
+import type { PaginationParams } from '@/types/common.types'
+
+const BASE_URL = '/admin/users'
+
+export const usersService = {
+  list: async (params?: PaginationParams): Promise<GetUserResponse> => {
+    const searchParams = new URLSearchParams()
+
+    if (params?.page) searchParams.set('page', String(params.page))
+    if (params?.per_page) searchParams.set('per_page', String(params.per_page))
+
+    const query = searchParams.toString()
+    const url = query ? `${BASE_URL}?${query}` : BASE_URL
+
+    return http.get<GetUserResponse>(url)
+  },
+
+  detail: async (userId: number | string): Promise<GetUserDetailResponse> => {
+    return http.get<GetUserDetailResponse>(`${BASE_URL}/${userId}`)
+  },
+}

+ 4 - 0
src/types/common.types.ts

@@ -0,0 +1,4 @@
+export interface PaginationParams {
+  page?: number
+  per_page?: number
+}

+ 79 - 0
src/types/users.types.ts

@@ -0,0 +1,79 @@
+export interface User {
+  id: number
+  is_me: boolean
+  first_name: string
+  last_name: string
+  full_name: string
+  phone: string
+  email: null
+  username: string
+  province_id: number
+  city_id: number
+  gender: number
+  birth_date: string
+  weight: number
+  height: number
+  foot_specialization: string
+  post_skill: string
+  skill_level: string
+  activity_history: number
+  team_name: null
+  favorite_iranian_team: string
+  favorite_foreign_team: string
+  shirt_number: number
+  bio: null
+  followers_count: number
+  following_count: number
+  post_count: number
+  avatar?: Avatar
+  created_at: string
+  updated_at: string
+}
+
+export interface UsersListMeta {
+  total?: number
+  per_page?: number
+  current_page?: number
+  last_page?: number
+}
+
+export interface GetUserResponse {
+  success: boolean
+  message: string
+  data: {
+    users: User[]
+    meta?: UsersListMeta
+  }
+}
+
+export interface Avatar {
+  name: string
+  url: string
+  hash: string
+  type: string
+  entity_slug: string
+}
+
+export interface Post {
+  id: number
+  user_id: number
+  state: string
+  caption: string
+  video: Avatar
+  thumbnail: null
+  likes_count: number
+  dislikes_count: number
+  views_count: number
+  comment_count: number
+  created_at: string
+  updated_at: string
+}
+
+export interface GetUserDetailResponse {
+  success: boolean
+  message: string
+  data: {
+    user: User
+    posts: Post[]
+  }
+}