@anmol0493/fullstack-app 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,10 +15,10 @@ This is a **full-stack template** designed to help developers quickly bootstrap
15
15
  ## Getting Started
16
16
 
17
17
  ### Prerequisites
18
- - [Node.js](https://nodejs.org/) (v16 or higher)
18
+ - [Node.js](https://nodejs.org/) (v20 or higher)
19
19
  - [npm](https://www.npmjs.com/)
20
20
 
21
21
  ### Installation
22
22
  - ```bash
23
23
  npx @anmol0493/fullstack-app my-project
24
- ```
24
+ ```
@@ -1,21 +1,29 @@
1
- import { useSelector } from "react-redux";
2
- import { actions, RootState } from "../redux/store";
3
- import { Button } from "./ui/Button";
4
1
  import { LogOut, TriangleAlert } from "lucide-react";
5
- import { cn } from "../lib/utils";
6
- import toast from "react-hot-toast";
7
2
  import { useState } from "react";
3
+ import toast from "react-hot-toast";
4
+ import { useDispatch, useSelector } from "react-redux";
5
+ import { cn } from "../lib/utils";
6
+ import { authApi } from "../redux/api/auth";
7
+ import { actions, RootState } from "../redux/store";
8
+ import { Button } from "./ui/Button";
8
9
  import { CommonAlertDialog } from "./ui/CommonAlertDialog";
9
10
 
10
11
  interface LayoutProps {
11
12
  children: React.ReactNode;
12
13
  }
13
14
 
15
+ const apiArray = [authApi];
16
+
14
17
  export const Layout = ({ children }: LayoutProps) => {
15
18
  const { currentUser } = useSelector((state: RootState) => state.auth);
16
19
  const [isDialogOpen, setIsDialogOpen] = useState(false);
17
20
 
21
+ const dispatch = useDispatch();
22
+
18
23
  const handleLogout = () => {
24
+ apiArray.forEach(api => {
25
+ dispatch(api.util.resetApiState());
26
+ });
19
27
  actions.auth.clearToken(null);
20
28
  toast.success("Logged out successfully");
21
29
  };
@@ -1,14 +1,14 @@
1
- import { clsx, type ClassValue } from "clsx";
2
- import { twMerge } from "tailwind-merge";
3
1
  import {
4
2
  BaseQueryFn,
5
3
  FetchArgs,
6
4
  fetchBaseQuery,
7
5
  FetchBaseQueryError
8
- } from "@reduxjs/toolkit/query/react";
9
- import { AUTH_TOKEN } from "./constants";
10
- import { actions } from "../redux/store";
11
- import toast from "react-hot-toast";
6
+ } from '@reduxjs/toolkit/query/react';
7
+ import { clsx, type ClassValue } from 'clsx';
8
+ import toast from 'react-hot-toast';
9
+ import { twMerge } from 'tailwind-merge';
10
+ import { clearToken } from '../redux/slice/auth';
11
+ import { AUTH_TOKEN } from './constants';
12
12
 
13
13
  export function cn(...inputs: ClassValue[]) {
14
14
  return twMerge(clsx(inputs));
@@ -21,7 +21,7 @@ export const isAuth = (): boolean => {
21
21
  }
22
22
 
23
23
  try {
24
- const decoded = JSON.parse(atob(token.split(".")[1]));
24
+ const decoded = JSON.parse(atob(token.split('.')[1]));
25
25
  const currentTime = Date.now() / 1000;
26
26
  return decoded.exp > currentTime;
27
27
  } catch (error) {
@@ -29,7 +29,7 @@ export const isAuth = (): boolean => {
29
29
  }
30
30
  };
31
31
 
32
- const Headers = () => localStorage.getItem(AUTH_TOKEN) || "";
32
+ const Headers = () => localStorage.getItem(AUTH_TOKEN) || '';
33
33
 
34
34
  export const baseQueryInterceptor = (
35
35
  baseUrl: string
@@ -37,7 +37,7 @@ export const baseQueryInterceptor = (
37
37
  const baseQuery = fetchBaseQuery({
38
38
  baseUrl: baseUrl,
39
39
  prepareHeaders: (headers) => {
40
- headers.set("Authorization", `Bearer ${Headers()}`);
40
+ headers.set('Authorization', `Bearer ${Headers()}`);
41
41
  return headers;
42
42
  }
43
43
  });
@@ -45,7 +45,7 @@ export const baseQueryInterceptor = (
45
45
  return async (args, api, extraOptions) => {
46
46
  const result = await baseQuery(args, api, extraOptions);
47
47
  if (result.error && result.error.status === 401) {
48
- actions.auth.clearToken(null);
48
+ api.dispatch(clearToken());
49
49
  }
50
50
 
51
51
  return result;
@@ -54,18 +54,18 @@ export const baseQueryInterceptor = (
54
54
 
55
55
  export const handleError = async (error: any) => {
56
56
  toast.error(
57
- error?.data?.message ? error.data.message : "Something went wrong"
57
+ error?.data?.message ? error.data.message : 'Something went wrong'
58
58
  );
59
59
  };
60
60
 
61
61
  export const handleSuccess = async (obj: any) => {
62
- toast.success(obj?.message ? obj.message : "Success");
62
+ toast.success(obj?.message ? obj.message : 'Success');
63
63
  };
64
64
 
65
65
  export const handleValue = (row: any, field: any) => {
66
- if (!field) return "-";
67
- if (typeof field === "function") return field(row) ?? "-";
66
+ if (!field) return '-';
67
+ if (typeof field === 'function') return field(row) ?? '-';
68
68
  return field
69
- .split(".")
70
- .reduce((acc: any, part: any) => acc && (acc[part] ?? "-"), row);
69
+ .split('.')
70
+ .reduce((acc: any, part: any) => acc && (acc[part] ?? '-'), row);
71
71
  };
@@ -1,6 +1,6 @@
1
- import { createSlice } from "@reduxjs/toolkit";
2
- import { User } from "../../types";
3
- import { AUTH_TOKEN } from "../../lib/constants";
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ import { AUTH_TOKEN } from '../../lib/constants';
3
+ import { User } from '../../types';
4
4
 
5
5
  interface AuthState {
6
6
  currentUser: null | User;
@@ -15,7 +15,7 @@ const initialState: AuthState = {
15
15
  };
16
16
 
17
17
  export const authSlice = createSlice({
18
- name: "auth",
18
+ name: 'auth',
19
19
  initialState,
20
20
  reducers: {
21
21
  setCurrentUser: (state, action) => {
@@ -35,5 +35,5 @@ export const authSlice = createSlice({
35
35
  }
36
36
  });
37
37
 
38
- export const { setIsLoading, setCurrentUser } = authSlice.actions;
38
+ export const { setIsLoading, setCurrentUser, clearToken } = authSlice.actions;
39
39
  export default authSlice.reducer;
@@ -1,19 +1,26 @@
1
- import { defineConfig } from 'vite';
2
- import react from '@vitejs/plugin-react-swc';
3
1
  import tailwindcss from '@tailwindcss/vite';
2
+ import react from '@vitejs/plugin-react-swc';
3
+ import path from 'path';
4
+ import { defineConfig, loadEnv } from 'vite';
4
5
 
5
- const apiUrl = import.meta.env.VITE_API_URL;
6
+ export default defineConfig(({ mode }) => {
7
+ const env = loadEnv(mode, process.cwd(), '');
6
8
 
7
- // https://vite.dev/config/
8
- export default defineConfig({
9
- plugins: [react(), tailwindcss()],
10
- server: {
11
- proxy: {
12
- '/api': {
13
- target: apiUrl,
14
- changeOrigin: true,
15
- rewrite: (path) => path.replace(/^\/api/, '')
9
+ return {
10
+ plugins: [react(), tailwindcss()],
11
+ resolve: {
12
+ alias: {
13
+ '@': path.resolve(__dirname, './src')
14
+ }
15
+ },
16
+ server: {
17
+ proxy: {
18
+ '/api': {
19
+ target: env.VITE_API_URL,
20
+ changeOrigin: true,
21
+ rewrite: (path) => path.replace(/^\/api/, '')
22
+ }
16
23
  }
17
24
  }
18
- }
25
+ };
19
26
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anmol0493/fullstack-app",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "A full-stack template with Vite React frontend and Express/NestJS backend options.",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/scripts/setup.js CHANGED
@@ -4,7 +4,7 @@ import * as fs from 'fs';
4
4
  import * as path from 'path';
5
5
  import enquirer from 'enquirer'; // Install enquirer: npm install enquirer
6
6
  const { prompt } = enquirer;
7
- // import { execa } from 'execa'; // Install execa: npm install execa
7
+ import { execa } from 'execa'; // Install execa: npm install execa
8
8
  import { fileURLToPath } from 'url';
9
9
  import { dirname } from 'path';
10
10