first commit

This commit is contained in:
liamzi
2025-01-21 10:57:59 +08:00
commit 83096f7c9e
22 changed files with 8799 additions and 0 deletions

48
src/hook/fetchFn.tsx Normal file
View File

@@ -0,0 +1,48 @@
import { useCallback, useState } from "react";
const useHttpClient = (baseurl:string) => {
interface ApiError extends Error {
status?: number;
message: string;
}
const httpClient = useCallback(async (url: string, options: any = {},token:string='') => {
try {
const defaultOptions: any = {
method: "GET",
...options,
headers: {
...options.headers,
Authorization: `Bearer ${token}`,
},
};
if (options.body instanceof FormData) {
delete defaultOptions.headers['content-type'];
} else {
defaultOptions.headers['content-type'] = 'application/json';
}
const response = await fetch(`${baseurl}${url}`, defaultOptions);
const responseBody = await response.text() as any;
if (response.status === 401) {
const errorData: any = JSON.parse(responseBody);
const error: ApiError = new Error(errorData.message);
error.status = response.status;
throw error;
}
if ([400, 403, 500].includes(response.status)) {
const errorData: any = JSON.parse(responseBody);
const error = new Error(errorData.message);
(error as any).status = response.status;
throw error;
}
return JSON.parse(responseBody);
} catch (error) {
if (!(error instanceof Error) || !(error as any).status) {
console.error("Request failed:", error);
}
throw error;
}
}, []);
return { httpClient };
};
export default useHttpClient;

29
src/hook/i18n.ts Normal file
View File

@@ -0,0 +1,29 @@
import i18next from 'i18next';
import { initReactI18next } from 'react-i18next';
import { translations } from '../locales/translations';
import { storage } from './useStore';
const i18n = i18next;
i18n.use(initReactI18next).init({
lng: "en",
fallbackLng: "tw",
debug: false,
interpolation: {
escapeValue: false
},
resources: {
'zh-CN': { translation: translations['zh-CN'] },
'zh-TW': { translation: translations['zh-TW'] },
'en': { translation: translations['en'] },
'ja': { translation: translations['ja'] },
'ko': { translation: translations['ko'] }
},
})
storage.get('language').then((res:any)=>{
if(res){
i18n.changeLanguage(res)
}
})
export default i18n;

62
src/hook/supabase.ts Normal file
View File

@@ -0,0 +1,62 @@
import { createClient, SupabaseClient } from "@supabase/supabase-js";
import { storage } from "./useStore";
import { onlyStandalone } from '../utils/getbaseurl'
// 定义环境变量的默认值
const SUPABASE_URL = process.env.REACT_SUPABASE_URL || '';
const SUPABASE_ANON_KEY = process.env.REACT_SUPABASE_ANON_KEY || '';
let supabase: any = null;
export const getSupabaseClient = (): SupabaseClient => {
if (!supabase&&!onlyStandalone) {
supabase = createClient(
SUPABASE_URL,
SUPABASE_ANON_KEY,
{
db: { schema: "limq" },
auth: {
storage: storageAdapter,
persistSession: true,
autoRefreshToken: true,
},
realtime: {
params: {
eventsPerSecond: 10,
},
}
}
);
}
return supabase;
};
const storageAdapter = {
getItem: async (key: string) => {
try {
const result: any = await storage.get(key);
return result || null;
} catch (error) {
console.error("Storage get error:", error);
return null;
}
},
setItem: async (key: string, value: string) => {
try {
await storage.set(key, value);
} catch (error) {
console.error("Storage set error:", error);
}
},
removeItem: async (key: string) => {
try {
await storage.remove(key);
} catch (error) {
console.error("Storage remove error:", error);
}
},
};
export const clearSupabaseInstance = () => {
supabase = null;
};

60
src/hook/useFile.tsx Normal file
View File

@@ -0,0 +1,60 @@
import { message } from 'antd';
export const useUpload = (supabaseClient: any) => {
const upload = async (file: any, bucket: string, name: string) => {
if (!file) return;
try {
const timestamp = Date.now();
// 处理文件名
const cleanFileName = name?.replace(/[^a-zA-Z0-9.-]/g, '_'); // 清理特殊字符
// 确保文件名不为空且包含扩展名
const fileExtension = file.type === 'application/pdf' ? '.pdf' :
file.type === 'image/gif' ? '.gif' :
'.file'; // 默认扩展名
// 组合最终的文件名
const uniqueFileName = cleanFileName
? `${timestamp}_${cleanFileName}${cleanFileName.includes('.') ? '' : fileExtension}`
: `${timestamp}${fileExtension}`;
const { data, error } = await supabaseClient
.storage
.from(bucket)
.upload(uniqueFileName, file, {
cacheControl: '3600',
});
if (error) {
throw new Error(error.message);
}
message.success('文件上传成功');
return data?.path;
} catch (error: any) {
throw new Error(error.message);
}
};
return { upload };
};
export const useGetPublicUrl = (supabaseClient:any) => {
const getPublicUrl = async (filePath: string, bucket: string) => {
const { data: urlData, error: urlError } = supabaseClient
.storage
.from(bucket) // 指定存储桶名称
.getPublicUrl(filePath);
if (urlError) {
message.error(`获取公共 URL 失败: ${urlError.message}`);
return null; // 如果获取失败,返回 null
} else {
return urlData?.publicUrl; // 成功时返回公共 URL
}
};
return { getPublicUrl };
};

85
src/hook/useStore.tsx Normal file
View File

@@ -0,0 +1,85 @@
interface StorageMessage {
type: "setStorage" | "getStorage" | "removeStorage";
key: string;
value?: any;
}
// 统一的发送消息函数
const sendMessageToFigma = (type: string, data?: any) => {
parent.postMessage({ pluginMessage: { type, ...data } }, '*');
};
export const storage = {
set: async (key: string, value: any) => {
try {
return new Promise((resolve, reject) => {
const messageHandler = (event: MessageEvent) => {
const msg = event.data.pluginMessage;
if (msg?.type === 'storageSet') {
window.removeEventListener('message', messageHandler);
if (msg.success) {
resolve(true);
} else {
reject(msg.error);
}
}
};
window.addEventListener('message', messageHandler);
// 发送设置存储的消息
sendMessageToFigma('setStorage', { key, value });
});
} catch (error) {
console.log(error, '222222');
}
},
get: async (key: string) => {
return new Promise((resolve, reject) => {
try {
const messageHandler = (event: MessageEvent) => {
const msg = event.data.pluginMessage;
if (msg?.type === 'storageGet') {
window.removeEventListener('message', messageHandler);
if (msg.value !== undefined) {
resolve(msg.value);
} else {
reject(msg.error);
}
}
};
window.addEventListener('message', messageHandler);
// 发送获取存储的消息
sendMessageToFigma('getStorage', { key });
} catch (error) {
reject(null);
console.log(error, 'getgetgetget4444');
}
});
},
remove: async (key: string) => {
try {
return new Promise((resolve, reject) => {
const messageHandler = (event: MessageEvent) => {
const msg = event.data.pluginMessage;
if (msg?.type === 'storageRemoved') {
window.removeEventListener('message', messageHandler);
if (msg.success) {
resolve(true);
} else {
reject(msg.error);
}
}
};
window.addEventListener('message', messageHandler);
// 发送删除存储的消息
sendMessageToFigma('removeStorage', { key });
});
} catch (error) {
console.error('Failed to remove storage:', error);
}
},
};