base structure

This commit is contained in:
hamid zarghami
2025-08-03 09:12:48 +03:30
parent 866618a5bc
commit 61a934074c
9 changed files with 234 additions and 6 deletions
+35
View File
@@ -0,0 +1,35 @@
'use client'
import { IApiErrorRepsonse } from '@/types/error.types'
import { QueryClient, QueryClientProvider, HydrationBoundary, QueryCache } from '@tanstack/react-query'
import { ReactNode, useState } from 'react'
import { removeToken } from './func'
import { useSharedStore } from '@/share/store/sharedStore'
export default function QueryProvider({ children }: { children: ReactNode }) {
const { setIsLogin } = useSharedStore()
const [client] = useState(() => new QueryClient({
queryCache: new QueryCache({
onError: async (error: IApiErrorRepsonse) => {
if (error.response?.status === 401) {
removeToken()
setIsLogin(false)
}
}
}),
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // داده‌ها برای 5 دقیقه معتبر هستند
}
}
}))
return (
<QueryClientProvider client={client}>
<HydrationBoundary state={null}>
{children}
</HydrationBoundary>
</QueryClientProvider>
)
}
+2
View File
@@ -0,0 +1,2 @@
export const TOKEN_NAME = "sh_token";
export const REFRESH_TOKEN_NAME = "sh_refresh_token";
+96
View File
@@ -0,0 +1,96 @@
import { TOKEN_NAME, REFRESH_TOKEN_NAME } from "./const";
export function isEmail(input: string): boolean {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
return emailRegex.test(input);
}
export function NumberFormat(number: number): string {
return Intl.NumberFormat("fa-IR").format(number);
// return Intl.NumberFormat("fa-IR").format(number);
}
export const timeAgo = (date: string | Date): string => {
const now = new Date();
const past = new Date(date);
const diff = Math.floor((now.getTime() - past.getTime()) / 1000); // اختلاف بر حسب ثانیه
const units = [
{ name: "سال", value: 60 * 60 * 24 * 365 },
{ name: "ماه", value: 60 * 60 * 24 * 30 },
{ name: "روز", value: 60 * 60 * 24 },
{ name: "ساعت", value: 60 * 60 },
{ name: "دقیقه", value: 60 },
{ name: "ثانیه", value: 1 },
];
for (const unit of units) {
const amount = Math.floor(diff / unit.value);
if (amount >= 1) return `${amount} ${unit.name} پیش`;
}
return "همین الان";
};
export const getToken = async () => {
return localStorage.getItem(TOKEN_NAME);
};
export const getRefreshToken = () => {
return localStorage.getItem(REFRESH_TOKEN_NAME);
};
export const setToken = (token: string) => {
localStorage.setItem(TOKEN_NAME, token);
};
export const setRefreshToken = (refreshToken: string) => {
localStorage.setItem(REFRESH_TOKEN_NAME, refreshToken);
};
export const removeToken = () => {
localStorage.removeItem(TOKEN_NAME);
};
export const removeRefreshToken = () => {
localStorage.removeItem(REFRESH_TOKEN_NAME);
};
export function toJalaliDate(
date: Date | string | number,
options?: Intl.DateTimeFormatOptions,
locale: string = "fa-IR-u-ca-persian"
): string {
const parsedDate = new Date(date);
if (isNaN(parsedDate.getTime())) {
return "";
throw new Error("Invalid date provided to toJalaliDate");
}
const defaultOptions: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "numeric",
day: "numeric",
// weekday: "long",
// hour: "numeric",
// minute: "numeric",
};
const formatter = new Intl.DateTimeFormat(locale, {
...defaultOptions,
...options,
});
return formatter.format(parsedDate);
}
export function limitHtmlWords(htmlString: string, wordLimit: number): string {
// پاک کردن تگ‌ها
const plainText = htmlString.replace(/<[^>]*>/g, "");
// تقسیم و محدود کردن کلمات
const words = plainText.split(/\s+/).slice(0, wordLimit);
const result = words.join(" ") + "...";
return result;
}
+9
View File
@@ -0,0 +1,9 @@
import { create } from "zustand";
import { SharedStoreType } from "../types/SharedTypes";
export const useSharedStore = create<SharedStoreType>((set) => ({
openSidebar: false,
setOpenSidebar: (value) => set({ openSidebar: value }),
isLogin: false,
setIsLogin: (value) => set({ isLogin: value }),
}));
+37
View File
@@ -0,0 +1,37 @@
export type SharedStoreType = {
openSidebar: boolean;
setOpenSidebar: (value: boolean) => void;
isLogin: boolean;
setIsLogin: (value: boolean) => void;
};
export interface ApiResponse<T> {
statusCode: number;
success: boolean;
data: T;
}
export type UserMeResponseType = ApiResponse<{
user: {
id: string;
createdAt: string;
updatedAt: string;
firstName: string;
lastName: string;
email: string;
emailVerified: boolean;
phone: string;
birthDate: string;
nationalCode: string;
financialType: string;
profilePic: string | null;
userName: string | null;
roles: Array<{
id: string;
createdAt: string;
name: string;
// Add other role properties as needed
}>;
};
}>;
+14
View File
@@ -0,0 +1,14 @@
import { DefaultError } from "@tanstack/react-query";
import { IBaseResponse } from "./response.types";
interface IError {
message: string[];
}
export interface IErrorResponse extends IBaseResponse {
error: IError;
}
export interface IApiErrorRepsonse extends DefaultError {
response?: IErrorResponse;
}
+7
View File
@@ -0,0 +1,7 @@
export interface IBaseResponse {
status: number;
success: boolean;
}
export interface IResponse<T> extends IBaseResponse {
data: T;
}