Skip to content

Commit

Permalink
Merge pull request #10 from sankaSanjeeva/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
sankaSanjeeva authored Oct 5, 2024
2 parents 07c2928 + 8ddcd1a commit 75b2c96
Show file tree
Hide file tree
Showing 12 changed files with 1,133 additions and 1,042 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 1.3.0 (October 04, 2024)

### New features

- Add unit testing

### Bug Fixing

- Fix mobile responsive issues
- Clean query cache when user logout

## 1.2.0 (September 14, 2024)

### New features
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "react-boilerplate",
"private": true,
"version": "1.2.0",
"version": "1.3.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down Expand Up @@ -38,6 +38,7 @@
"react-dropzone": "^14.2.3",
"react-hook-form": "^7.52.2",
"react-router-dom": "^6.24.1",
"react-syntax-highlighter": "^15.5.0",
"tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.23.8"
Expand All @@ -51,6 +52,7 @@
"@types/node": "^20.14.10",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/react-syntax-highlighter": "^15.5.13",
"@typescript-eslint/eslint-plugin": "^7.15.0",
"@typescript-eslint/parser": "^7.15.0",
"@vitejs/plugin-react-swc": "^3.5.0",
Expand Down
20 changes: 8 additions & 12 deletions src/components/header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,13 @@ export default function Header() {
const { token, manageLogout } = useAuth();
const { theme, setTheme } = useTheme();

const handleLoginClick = () => {
manageLogout();
};

const changeTheme = (newTheme: typeof theme) => {
setTheme(newTheme);
};

return (
<header className="sticky top-0 z-10 backdrop-blur border-b border-slate-900/10 dark:border-slate-50/10 bg-white dark:bg-slate-900/75">
<div className="max-w-screen-xl mx-auto flex items-center py-3 px-10">
<div className="max-w-screen-xl mx-auto flex items-center py-3 px-3 sm:px-5 md:px-10">
<Link to="/home" className="inline-flex gap-5">
<img src="/react.svg" alt="icon" />
<h1 className="text-xl md:text-2xl font-semibold">
Expand All @@ -54,7 +50,7 @@ export default function Header() {
to="/home"
className={({ isActive }) =>
cn(
'mx-10 font-semibold transition-colors',
'mx-5 md:mx-10 font-semibold transition-colors',
isActive
? 'text-gray-900 dark:text-gray-100'
: 'text-gray-900/50 dark:text-gray-100/75'
Expand All @@ -65,7 +61,7 @@ export default function Header() {
</NavLink>
)}

<div className="flex items-center gap-2 ml-auto">
<div className="flex items-center gap-1 md:gap-2 ml-auto">
{token && (
<Dialog>
<DialogTrigger asChild>
Expand All @@ -75,7 +71,7 @@ export default function Header() {
variant="ghost"
data-testid="logout-button"
>
<LogoutIcon />
<LogoutIcon className="h-5 w-5 md:h-6 md:w-6" />
</Button>
</DialogTrigger>
<DialogContent>
Expand All @@ -90,7 +86,7 @@ export default function Header() {
<Button variant="outline">Cancel</Button>
</DialogClose>
<DialogClose asChild>
<Button onClick={handleLoginClick}>Logout</Button>
<Button onClick={manageLogout}>Logout</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
Expand All @@ -102,11 +98,11 @@ export default function Header() {
<Button size="icon" variant="ghost" data-testid="theme-button">
{/* eslint-disable-next-line no-nested-ternary */}
{theme === 'dark' ? (
<DarkModeIcon />
<DarkModeIcon className="h-5 w-5 md:h-6 md:w-6" />
) : theme === 'light' ? (
<LightModeIcon />
<LightModeIcon className="h-5 w-5 md:h-6 md:w-6" />
) : (
<ComputerIcon />
<ComputerIcon className="h-5 w-5 md:h-6 md:w-6" />
)}
</Button>
</DropdownMenuTrigger>
Expand Down
28 changes: 15 additions & 13 deletions src/contexts/__tests__/auth.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { PropsWithChildren } from 'react';
import { render, renderHook, screen } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { afterEach, describe, expect, test, vi } from 'vitest';
import { TOKEN_STORAGE_KEY } from '@/constants';
import { AuthProvider, useAuth } from '../auth';
Expand All @@ -13,6 +15,13 @@ vi.mock(import('react-router-dom'), async (importOriginal) => {
};
});

const queryClient = new QueryClient();
const wrapper = ({ children }: PropsWithChildren) => (
<QueryClientProvider client={queryClient}>
<AuthProvider>{children}</AuthProvider>
</QueryClientProvider>
);

function TestComponent() {
const { token } = useAuth();
return <div>{token ? 'Authenticated' : 'Not Authenticated'}</div>;
Expand All @@ -27,7 +36,8 @@ describe('useAuth', () => {
render(
<AuthProvider>
<TestComponent />
</AuthProvider>
</AuthProvider>,
{ wrapper }
);

expect(screen.getByText('Not Authenticated')).toBeInTheDocument();
Expand All @@ -44,25 +54,19 @@ describe('AuthProvider', () => {
test('should initialize token from localStorage when component mounts', () => {
localStorage.setItem(TOKEN_STORAGE_KEY, 'test-token');

const { result } = renderHook(useAuth, {
wrapper: ({ children }) => <AuthProvider>{children}</AuthProvider>,
});
const { result } = renderHook(useAuth, { wrapper });

expect(result.current.token).toBe('test-token');
});

test('should throw error when token is not provided in manageLogin', () => {
const { result } = renderHook(useAuth, {
wrapper: ({ children }) => <AuthProvider>{children}</AuthProvider>,
});
const { result } = renderHook(useAuth, { wrapper });

expect(() => result.current.manageLogin('')).toThrow('A token is required');
});

test('should navigate to home when token is provided in manageLogin', () => {
const { result } = renderHook(useAuth, {
wrapper: ({ children }) => <AuthProvider>{children}</AuthProvider>,
});
const { result } = renderHook(useAuth, { wrapper });

result.current.manageLogin('sample-token');

Expand All @@ -73,9 +77,7 @@ describe('AuthProvider', () => {
});

test('should navigate to auth when call manageLogout', () => {
const { result } = renderHook(useAuth, {
wrapper: ({ children }) => <AuthProvider>{children}</AuthProvider>,
});
const { result } = renderHook(useAuth, { wrapper });

result.current.manageLogout();

Expand Down
6 changes: 5 additions & 1 deletion src/contexts/auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
useState,
} from 'react';
import { useNavigate } from 'react-router-dom';
import { useQueryClient } from '@tanstack/react-query';
import { TOKEN_STORAGE_KEY } from '@/constants';

type AuthProviderState = {
Expand All @@ -23,6 +24,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {

const navigate = useNavigate();

const queryClient = useQueryClient();

const manageLogin = useCallback(
(tkn: string) => {
if (!tkn) {
Expand All @@ -39,8 +42,9 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const manageLogout = useCallback(() => {
localStorage.removeItem(TOKEN_STORAGE_KEY);
setToken(null);
queryClient.clear();
navigate('/auth');
}, [navigate]);
}, [navigate, queryClient]);

const value = useMemo(
() => ({ token, manageLogin, manageLogout }),
Expand Down
56 changes: 44 additions & 12 deletions src/modules/home/docs/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,45 @@
import { useMemo } from 'react';
import { MDXProvider } from '@mdx-js/react';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import {
darcula,
duotoneLight,
} from 'react-syntax-highlighter/dist/esm/styles/prism';
import { useTheme } from '@/contexts';

function InlineCode({ children }: { children?: React.ReactNode }) {
return (
<code className="py-0.5 px-2 text-sm rounded bg-[#faf8f5] dark:bg-[#2b2b2b]">
{children}
</code>
);
}

function BlockCode({ children }: { children?: React.ReactNode }) {
const { theme } = useTheme();

const style = useMemo(() => {
if (theme === 'system') {
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)')
.matches
? darcula
: duotoneLight;

return systemTheme;
}
return theme === 'dark' ? darcula : duotoneLight;
}, [theme]);

return (
<SyntaxHighlighter
language="javascript"
style={style}
customStyle={{ borderRadius: 8, maxHeight: 500, overflowY: 'auto' }}
>
{`${children}`}
</SyntaxHighlighter>
);
}

const components = {
h1: (props: React.HTMLAttributes<HTMLElement>) => (
Expand All @@ -24,18 +65,9 @@ const components = {
{...props}
/>
),
pre: (props: React.HTMLAttributes<HTMLElement>) => (
<pre
className="mb-4 mt-6 p-4 max-h-[500px] overflow-x-auto rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-100 dark:bg-gray-900"
{...props}
/>
),
code: (props: React.HTMLAttributes<HTMLElement>) => (
<code
className="py-1 px-2 font-mono text-sm bg-gray-100 dark:bg-gray-900"
{...props}
/>
),
code: InlineCode, // Handles inline code
// eslint-disable-next-line @typescript-eslint/no-explicit-any
pre: (props: any) => <BlockCode {...props.children.props} />, // Handles block code
ul: (props: React.HTMLAttributes<HTMLElement>) => (
<ul className="my-6 ml-6 list-disc" {...props} />
),
Expand Down
4 changes: 2 additions & 2 deletions src/modules/user/pages/user-create-edit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export default function UserCreate() {
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="flex flex-col w-full gap-5 p-10"
className="flex flex-col w-full gap-5 p-2 sm:p-5 md:p-10"
>
<div className="flex justify-between">
<h1 className="text-2xl font-bold">{userId ? 'Edit' : 'New'} User</h1>
Expand Down Expand Up @@ -108,7 +108,7 @@ export default function UserCreate() {
onChange={(files) => {
field.onChange(files?.[0]);
}}
className="w-80 h-80"
className="w-full max-w-80 h-80"
placeholder="Drag 'n' drop here, or click to select a profile picture"
/>
</FormControl>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { Skeleton } from '@/components/ui/skeleton';

export default function UserEditSkeleton() {
return (
<div className="flex flex-col w-full gap-5 p-10">
<div className="flex flex-col w-full gap-5 p-2 sm:p-5 md:p-10">
<div className="flex justify-between">
<Skeleton className="w-28 h-10 rounded-md" />
<Skeleton className="w-20 h-10 rounded-md" />
</div>

<div className="p-[25px]">
<Skeleton className="w-80 h-80 rounded-md" />
<Skeleton className="w-full max-w-80 h-80 rounded-md" />
</div>

<div className="mt-[25px]">
Expand Down
4 changes: 2 additions & 2 deletions src/modules/user/pages/user-list/table-skeleton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default function TableSkeleton() {
<thead>
<tr>
<th className="p-3 first:pl-6 last:pr-6 w-[56px]">
<span />
<Skeleton className="w-5 h-5 rounded" />
</th>
<th className="p-3 first:pl-6 last:pr-6 w-[80px]">
<span />
Expand All @@ -29,7 +29,7 @@ export default function TableSkeleton() {
className="[&:not(:last-child)]:border-b-2 border-b-transparent"
>
<td className="p-3 first:pl-6 last:pr-6">
<span />
<Skeleton className="w-5 h-5 rounded" />
</td>
<td className="p-3 first:pl-6 last:pr-6">
<Skeleton className="w-14 h-14 rounded-full" />
Expand Down
2 changes: 1 addition & 1 deletion src/modules/user/pages/user-view/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function UserView() {
}

return (
<div className="flex flex-col w-full gap-5 p-10">
<div className="flex flex-col w-full gap-5 p-2 sm:p-6 md:p-10">
<div className="flex justify-between">
<h1 className="text-2xl font-bold">Profile</h1>
<Link to="edit">
Expand Down
2 changes: 1 addition & 1 deletion src/modules/user/pages/user-view/user-view-skeleton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Skeleton } from '@/components/ui/skeleton';

export default function UserViewSkeleton() {
return (
<div className="flex flex-col gap-5 p-10 w-full">
<div className="flex flex-col gap-5 p-2 sm:p-6 md:p-10">
<div className="flex justify-between">
<Skeleton className="w-[74px] h-10 rounded-lg" />
<Skeleton className="w-[88px] h-10 rounded-lg" />
Expand Down
Loading

0 comments on commit 75b2c96

Please sign in to comment.