Skip to content

Commit

Permalink
feat: react query integration
Browse files Browse the repository at this point in the history
  • Loading branch information
aseerkt committed Jun 27, 2024
1 parent b1be052 commit 336bffd
Show file tree
Hide file tree
Showing 66 changed files with 1,629 additions and 695 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/client-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: mChat Server CI

on:
push:
branches:
- main
paths:
- .github/workflows/client-ci.yml
- client/*


jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'

- name: Install deps
run: pnpm i --filter client

- name: Lint
run: pnpm --filter client lint

- name: Build
run: pnpm --filter client build



36 changes: 36 additions & 0 deletions .github/workflows/server-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: mChat Server CI

on:
push:
branches:
- main
paths:
- .github/workflows/server-ci.yml
- server/*


jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'

- name: Install dependencies
run: pnpm i --filter server

- name: Build
run: pnpm --filter server build



4 changes: 4 additions & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

pnpm run commitlint ${1}
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

pnpm build
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

- Spin up entire stack (redis, mongo, client, server)
```bash
docker compose -f docker-compose.prod.yml up
docker compose -f docker-compose.prod.yml up --build
```
- Go to [http://localhost:3000](http://localhost:3000)

Expand Down
1 change: 1 addition & 0 deletions client/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = {
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
'plugin:@tanstack/eslint-plugin-query/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
Expand Down
3 changes: 3 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
"preview": "vite preview"
},
"dependencies": {
"@tanstack/react-query": "^5.48.0",
"clsx": "^2.1.1",
"cva": "npm:class-variance-authority@^0.7.0",
"immer": "^10.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.13",
Expand All @@ -20,6 +22,7 @@
"tailwind-merge": "^2.3.0"
},
"devDependencies": {
"@tanstack/eslint-plugin-query": "^5.47.0",
"@types/node": "^20.14.5",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
Expand Down
5 changes: 1 addition & 4 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Outlet } from 'react-router-dom'
import { Toaster } from './components/Toaster'
import { useAuthRedirect } from './hooks/useAuthRedirect'
import { QueryCacheProvider } from './providers/QueryCacheProvider'
import { UserProvider } from './providers/UserProvider'

const AuthRedirect = () => {
Expand All @@ -13,9 +12,7 @@ function App() {
return (
<UserProvider>
<AuthRedirect />
<QueryCacheProvider>
<Outlet />
</QueryCacheProvider>
<Outlet />
<Toaster />
</UserProvider>
)
Expand Down
5 changes: 4 additions & 1 deletion client/src/components/Skeleton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ export const Skeleton = ({ className }: { className?: string }) => {
return (
<div
aria-label='loading-skeleton'
className={cn('w-full animate-pulse rounded bg-gray-300', className)}
className={cn(
'w-full shrink-0 animate-pulse rounded bg-gray-300',
className,
)}
></div>
)
}
2 changes: 1 addition & 1 deletion client/src/components/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useEffect } from 'react'
import { createPortal } from 'react-dom'

const toastVariants = cva(
'fixed flex text-white justify-between gap-4 md:max-w-[250px] shadow-lg border rounded p-3 bottom-6 z-10 transition-all',
'fixed flex text-white justify-between gap-4 md:min-w-[250px] shadow-lg border rounded p-3 bottom-6 z-10 transition-all',
{
variants: {
severity: {
Expand Down
13 changes: 0 additions & 13 deletions client/src/contexts/QueryCacheContext.tsx

This file was deleted.

17 changes: 17 additions & 0 deletions client/src/features/auth/auth.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export interface IUser {
_id: string
username: string
password: string
createdAt: string
updatedAt: string
}

export interface IUserResponse {
user: IUser
token: string
}

export interface IAuthMutationVariables {
username: string
password: string
}
14 changes: 14 additions & 0 deletions client/src/features/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { fetcher } from '@/utils/api'
import { IAuthMutationVariables } from './auth.interface'

export const login = async (payload: IAuthMutationVariables) =>
fetcher('users/login', {
method: 'POST',
body: JSON.stringify(payload),
})

export const signup = async (payload: IAuthMutationVariables) =>
fetcher(`users`, {
method: 'POST',
body: JSON.stringify(payload),
})
48 changes: 21 additions & 27 deletions client/src/features/auth/components/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
import { useMutation } from '@tanstack/react-query'
import { NavLink } from 'react-router-dom'
import { Button } from '../../../components/Button'
import { Input } from '../../../components/Input'
import { useAuthSetter } from '../../../hooks/useAuth'
import useForm from '../../../hooks/useForm'
import { useMutation } from '../../../hooks/useMutation'
import { useToast } from '../../../hooks/useToast'
import { IUser } from '../../../interfaces/user.interface'
import { setToken } from '../../../utils/token'
import { isRequired } from '../../../utils/validators'

interface LoginResponse {
user: IUser
token: string
}

interface LoginVariables {
username: string
password: string
}
import { IAuthMutationVariables, IUserResponse } from '../auth.interface'
import { login } from '../auth.service'

const validators = {
username: [isRequired('Username is required')],
Expand All @@ -31,24 +22,27 @@ export const LoginForm = () => {
initialValues: { username: '', password: '' },
})

const { mutate: login, loading } = useMutation<LoginResponse, LoginVariables>(
'/api/users/login',
{ method: 'POST' },
)

const onSubmit = handleSubmit(async values => {
try {
const result = await login(values)
if (result?.user && result.token) {
setToken(result.token)
setAuth(result.user)
const { mutate: loginUser, isPending } = useMutation<
IUserResponse,
Error,
IAuthMutationVariables
>({
mutationFn: login,
onSuccess(data) {
if (data.user && data.token) {
setToken(data.token)
setAuth(data.user)
toast({ title: 'Login success', severity: 'success' })
}
} catch (error) {
toast({ title: (error as Error).message, severity: 'error' })
}
},
onError(error) {
console.log(error.message)
toast({ title: error.message, severity: 'error' })
},
})

const onSubmit = handleSubmit(loginUser)

return (
<form className='flex flex-col gap-4' onSubmit={onSubmit}>
<Input
Expand All @@ -65,7 +59,7 @@ export const LoginForm = () => {
{...register('password', validators.password)}
error={errors.password}
/>
<Button type='submit' disabled={loading}>
<Button type='submit' disabled={isPending}>
Continue
</Button>
<small>
Expand Down
45 changes: 19 additions & 26 deletions client/src/features/auth/components/SignUpForm.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
import { useMutation } from '@tanstack/react-query'
import { NavLink } from 'react-router-dom'
import { Button } from '../../../components/Button'
import { Input } from '../../../components/Input'
import { useAuthSetter } from '../../../hooks/useAuth'
import useForm from '../../../hooks/useForm'
import { useMutation } from '../../../hooks/useMutation'
import { useToast } from '../../../hooks/useToast'
import { IUser } from '../../../interfaces/user.interface'
import { setToken } from '../../../utils/token'
import { isRequired } from '../../../utils/validators'

interface SignUpResponse {
user: IUser
token: string
}

interface SignUpVariables {
username: string
password: string
}
import { IAuthMutationVariables, IUserResponse } from '../auth.interface'
import { signup } from '../auth.service'

const validators = {
username: [isRequired('Username is required')],
Expand All @@ -31,24 +22,26 @@ export const SignUpForm = () => {
initialValues: { username: '', password: '' },
})

const { mutate: signup, loading } = useMutation<
SignUpResponse,
SignUpVariables
>('/api/users', { method: 'POST' })

const onSubmit = handleSubmit(async values => {
try {
const result = await signup(values)
if (result?.user && result.token) {
setToken(result.token)
setAuth(result.user)
const { mutate: signupUser, isPending } = useMutation<
IUserResponse,
Error,
IAuthMutationVariables
>({
mutationFn: signup,
onSuccess: data => {
if (data.user && data.token) {
setToken(data.token)
setAuth(data.user)
toast({ title: 'Login success', severity: 'success' })
}
} catch (error) {
},
onError(error) {
toast({ title: (error as Error).message, severity: 'error' })
}
},
})

const onSubmit = handleSubmit(signupUser)

return (
<form className='flex flex-col gap-4' onSubmit={onSubmit}>
<Input
Expand All @@ -65,7 +58,7 @@ export const SignUpForm = () => {
{...register('password', validators.password)}
error={errors.password}
/>
<Button type='submit' disabled={loading}>
<Button type='submit' disabled={isPending}>
Create account
</Button>
<small>
Expand Down
4 changes: 4 additions & 0 deletions client/src/features/chat/chat.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface ITypingUser {
_id: string
username: string
}
8 changes: 4 additions & 4 deletions client/src/features/chat/components/ChatHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logoutSvg from '../../../assets/logout-2-svgrepo-com.svg'
import { Logo } from '../../../components/Logo'
import { useAuthSetter } from '../../../hooks/useAuth'
import { removeToken } from '../../../utils/token'
import logoutSvg from '@/assets/logout-2-svgrepo-com.svg'
import { Logo } from '@/components/Logo'
import { useAuthSetter } from '@/hooks/useAuth'
import { removeToken } from '@/utils/token'

export const ChatHeader = () => {
const setAuth = useAuthSetter()
Expand Down
4 changes: 2 additions & 2 deletions client/src/features/chat/components/ChatUser.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useAuthState } from '../../../hooks/useAuth'
import { cn } from '../../../utils/style'
import { useAuthState } from '@/hooks/useAuth'
import { cn } from '@/utils/style'

export const ChatUser = ({ isConnected }: { isConnected: boolean }) => {
const auth = useAuthState()
Expand Down
Loading

0 comments on commit 336bffd

Please sign in to comment.