refactor(v4.0.0-alpha): beginning of a new era

This commit is contained in:
Amruth Pillai
2023-11-05 12:31:42 +01:00
parent 0ba6a444e2
commit 22933bd412
505 changed files with 81829 additions and 0 deletions

View File

@ -0,0 +1,25 @@
import { MessageDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
export const resendVerificationEmail = async () => {
const response = await axios.post<MessageDto, AxiosResponse<MessageDto>>(
"/auth/verify-email/resend",
);
return response.data;
};
export const useResendVerificationEmail = () => {
const {
error,
isPending: loading,
mutateAsync: resendVerificationEmailFn,
} = useMutation({
mutationFn: resendVerificationEmail,
});
return { resendVerificationEmail: resendVerificationEmailFn, loading, error };
};

View File

@ -0,0 +1,25 @@
import { MessageDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
export const verifyEmail = async (data: { token: string }) => {
const response = await axios.post<MessageDto, AxiosResponse<MessageDto>>(
`/auth/verify-email?token=${data.token}`,
);
return response.data;
};
export const useVerifyEmail = () => {
const {
error,
isPending: loading,
mutateAsync: verifyEmailFn,
} = useMutation({
mutationFn: verifyEmail,
});
return { verifyEmail: verifyEmailFn, loading, error };
};

View File

@ -0,0 +1,20 @@
export * from "./login";
export * from "./logout";
export * from "./refresh";
export * from "./register";
export * from "./update-password";
// Email Verification
export * from "./email-verification/resend-verify-email";
export * from "./email-verification/verify-email";
// Password Recovery
export * from "./password-recovery/forgot-password";
export * from "./password-recovery/reset-password";
// Two Factor Authentication
export * from "./two-factor-authentication/backup-otp";
export * from "./two-factor-authentication/disable";
export * from "./two-factor-authentication/enable";
export * from "./two-factor-authentication/setup";
export * from "./two-factor-authentication/verify-otp";

View File

@ -0,0 +1,40 @@
import { AuthResponseDto, LoginDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { useNavigate } from "react-router-dom";
import { axios } from "@/client/libs/axios";
import { queryClient } from "@/client/libs/query-client";
import { useAuthStore } from "@/client/stores/auth";
export const login = async (data: LoginDto) => {
const response = await axios.post<AuthResponseDto, AxiosResponse<AuthResponseDto>, LoginDto>(
"/auth/login",
data,
);
return response.data;
};
export const useLogin = () => {
const navigate = useNavigate();
const setUser = useAuthStore((state) => state.setUser);
const {
error,
isPending: loading,
mutateAsync: loginFn,
} = useMutation({
mutationFn: login,
onSuccess: (data) => {
if (data.status === "2fa_required") {
return navigate("/auth/verify-otp");
}
setUser(data.user);
queryClient.setQueryData(["user"], data.user);
},
});
return { login: loginFn, loading, error };
};

View File

@ -0,0 +1,31 @@
import { useMutation } from "@tanstack/react-query";
import { axios } from "@/client/libs/axios";
import { queryClient } from "@/client/libs/query-client";
import { useAuthStore } from "@/client/stores/auth";
export const logout = async () => {
await axios.post("/auth/logout");
};
export const useLogout = () => {
const setUser = useAuthStore((state) => state.setUser);
const {
error,
isPending: loading,
mutateAsync: logoutFn,
} = useMutation({
mutationFn: logout,
onSuccess: () => {
setUser(null);
queryClient.setQueryData(["user"], null);
},
onError: () => {
setUser(null);
queryClient.setQueryData(["user"], null);
},
});
return { logout: logoutFn, loading, error };
};

View File

@ -0,0 +1,26 @@
import { ForgotPasswordDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
export const forgotPassword = async (data: ForgotPasswordDto) => {
const response = await axios.post<void, AxiosResponse<void>, ForgotPasswordDto>(
"/auth/forgot-password",
data,
);
return response.data;
};
export const useForgotPassword = () => {
const {
error,
isPending: loading,
mutateAsync: forgotPasswordFn,
} = useMutation({
mutationFn: forgotPassword,
});
return { forgotPassword: forgotPasswordFn, loading, error };
};

View File

@ -0,0 +1,26 @@
import { ResetPasswordDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
export const resetPassword = async (data: ResetPasswordDto) => {
const response = await axios.post<void, AxiosResponse<void>, ResetPasswordDto>(
"/auth/reset-password",
data,
);
return response.data;
};
export const useResetPassword = () => {
const {
error,
isPending: loading,
mutateAsync: resetPasswordFn,
} = useMutation({
mutationFn: resetPassword,
});
return { resetPassword: resetPasswordFn, loading, error };
};

View File

@ -0,0 +1,8 @@
import { MessageDto } from "@reactive-resume/dto";
import { AxiosInstance, AxiosResponse } from "axios";
export const refresh = async (axios: AxiosInstance) => {
const response = await axios.post<MessageDto, AxiosResponse<MessageDto>>("/auth/refresh");
return response.data;
};

View File

@ -0,0 +1,34 @@
import { AuthResponseDto, RegisterDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
import { queryClient } from "@/client/libs/query-client";
import { useAuthStore } from "@/client/stores/auth";
export const register = async (data: RegisterDto) => {
const response = await axios.post<AuthResponseDto, AxiosResponse<AuthResponseDto>, RegisterDto>(
"/auth/register",
data,
);
return response.data;
};
export const useRegister = () => {
const setUser = useAuthStore((state) => state.setUser);
const {
error,
isPending: loading,
mutateAsync: registerFn,
} = useMutation({
mutationFn: register,
onSuccess: (data) => {
setUser(data.user);
queryClient.setQueryData(["user"], data.user);
},
});
return { register: registerFn, loading, error };
};

View File

@ -0,0 +1,43 @@
import { AuthResponseDto, TwoFactorBackupDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosError, AxiosResponse } from "axios";
import { toast } from "@/client/hooks/use-toast";
import { axios } from "@/client/libs/axios";
import { queryClient } from "@/client/libs/query-client";
import { useAuthStore } from "@/client/stores/auth";
export const backupOtp = async (data: TwoFactorBackupDto) => {
const response = await axios.post<
AuthResponseDto,
AxiosResponse<AuthResponseDto>,
TwoFactorBackupDto
>("/auth/2fa/backup", data);
return response.data;
};
export const useBackupOtp = () => {
const setUser = useAuthStore((state) => state.setUser);
const {
error,
isPending: loading,
mutateAsync: backupOtpFn,
} = useMutation({
mutationFn: backupOtp,
onSuccess: (data) => {
setUser(data.user);
queryClient.setQueryData(["user"], data.user);
},
onError: (error) => {
if (error instanceof AxiosError) {
const message = error.response?.data?.message || error.message;
toast({ variant: "error", title: message });
}
},
});
return { backupOtp: backupOtpFn, loading, error };
};

View File

@ -0,0 +1,23 @@
import { MessageDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
export const disable2FA = async () => {
const response = await axios.post<MessageDto, AxiosResponse<MessageDto>>("/auth/2fa/disable");
return response.data;
};
export const useDisable2FA = () => {
const {
error,
isPending: loading,
mutateAsync: disable2FAFn,
} = useMutation({
mutationFn: disable2FA,
});
return { disable2FA: disable2FAFn, loading, error };
};

View File

@ -0,0 +1,26 @@
import { BackupCodesDto, TwoFactorDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
export const enable2FA = async (data: TwoFactorDto) => {
const response = await axios.post<BackupCodesDto, AxiosResponse<BackupCodesDto>, TwoFactorDto>(
"/auth/2fa/enable",
data,
);
return response.data;
};
export const useEnable2FA = () => {
const {
error,
isPending: loading,
mutateAsync: enable2FAFn,
} = useMutation({
mutationFn: enable2FA,
});
return { enable2FA: enable2FAFn, loading, error };
};

View File

@ -0,0 +1,23 @@
import { MessageDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
export const setup2FA = async () => {
const response = await axios.post<MessageDto, AxiosResponse<MessageDto>>("/auth/2fa/setup");
return response.data;
};
export const useSetup2FA = () => {
const {
error,
isPending: loading,
mutateAsync: setup2FAFn,
} = useMutation({
mutationFn: setup2FA,
});
return { setup2FA: setup2FAFn, loading, error };
};

View File

@ -0,0 +1,42 @@
import { AuthResponseDto, TwoFactorDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosError, AxiosResponse } from "axios";
import { toast } from "@/client/hooks/use-toast";
import { axios } from "@/client/libs/axios";
import { queryClient } from "@/client/libs/query-client";
import { useAuthStore } from "@/client/stores/auth";
export const verifyOtp = async (data: TwoFactorDto) => {
const response = await axios.post<AuthResponseDto, AxiosResponse<AuthResponseDto>, TwoFactorDto>(
"/auth/2fa/verify",
data,
);
return response.data;
};
export const useVerifyOtp = () => {
const setUser = useAuthStore((state) => state.setUser);
const {
error,
isPending: loading,
mutateAsync: verifyOtpFn,
} = useMutation({
mutationFn: verifyOtp,
onSuccess: (data) => {
setUser(data.user);
queryClient.setQueryData(["user"], data.user);
},
onError: (error) => {
if (error instanceof AxiosError) {
const message = error.response?.data?.message || error.message;
toast({ variant: "error", title: message });
}
},
});
return { verifyOtp: verifyOtpFn, loading, error };
};

View File

@ -0,0 +1,26 @@
import { MessageDto, UpdatePasswordDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
export const updatePassword = async (data: UpdatePasswordDto) => {
const response = await axios.patch<MessageDto, AxiosResponse<MessageDto>, UpdatePasswordDto>(
"/auth/password",
data,
);
return response.data;
};
export const useUpdatePassword = () => {
const {
error,
isPending: loading,
mutateAsync: updatePasswordFn,
} = useMutation({
mutationFn: updatePassword,
});
return { updatePassword: updatePasswordFn, loading, error };
};

View File

@ -0,0 +1,30 @@
import { openai } from "./client";
const PROMPT = `You are an AI writing assistant specialized in writing copy for resumes.
Do not return anything else except the text you improved. It should not begin with a newline. It should not have any prefix or suffix text.
Change the tone of the following paragraph to be {mood}:
Text: """{input}"""
Revised Text: """`;
type Mood = "casual" | "professional" | "confident" | "friendly";
export const changeTone = async (text: string, mood: Mood) => {
const prompt = PROMPT.replace("{mood}", mood).replace("{input}", text);
const result = await openai().completions.create({
prompt,
model: "gpt-3.5-turbo",
max_tokens: 1024,
temperature: 0.5,
stop: ['"""'],
n: 1,
});
if (result.choices.length === 0) {
throw new Error("OpenAI did not return any choices for your text.");
}
return result.choices[0].text;
};

View File

@ -0,0 +1,18 @@
import { OpenAI } from "openai";
import { useOpenAiStore } from "@/client/stores/openai";
export const openai = () => {
const { apiKey } = useOpenAiStore.getState();
if (!apiKey) {
throw new Error(
"Your OpenAI API Key has not been set yet. Please go to your account settings to enable OpenAI Integration.",
);
}
return new OpenAI({
apiKey,
dangerouslyAllowBrowser: true,
});
};

View File

@ -0,0 +1,28 @@
import { openai } from "./client";
const PROMPT = `You are an AI writing assistant specialized in writing copy for resumes.
Do not return anything else except the text you improved. It should not begin with a newline. It should not have any prefix or suffix text.
Just fix the spelling and grammar of the following paragraph, do not change the meaning:
Text: """{input}"""
Revised Text: """`;
export const fixGrammar = async (text: string) => {
const prompt = PROMPT.replace("{input}", text);
const result = await openai().completions.create({
prompt,
model: "gpt-3.5-turbo",
max_tokens: 1024,
temperature: 0,
stop: ['"""'],
n: 1,
});
if (result.choices.length === 0) {
throw new Error("OpenAI did not return any choices for your text.");
}
return result.choices[0].text;
};

View File

@ -0,0 +1,28 @@
import { openai } from "./client";
const PROMPT = `You are an AI writing assistant specialized in writing copy for resumes.
Do not return anything else except the text you improved. It should not begin with a newline. It should not have any prefix or suffix text.
Improve the writing of the following paragraph:
Text: """{input}"""
Revised Text: """`;
export const improveWriting = async (text: string) => {
const prompt = PROMPT.replace("{input}", text);
const result = await openai().completions.create({
prompt,
model: "gpt-3.5-turbo",
max_tokens: 1024,
temperature: 0,
stop: ['"""'],
n: 1,
});
if (result.choices.length === 0) {
throw new Error("OpenAI did not return any choices for your text.");
}
return result.choices[0].text;
};

View File

@ -0,0 +1,35 @@
import { CreateResumeDto, ResumeDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
import { queryClient } from "@/client/libs/query-client";
export const createResume = async (data: CreateResumeDto) => {
const response = await axios.post<ResumeDto, AxiosResponse<ResumeDto>, CreateResumeDto>(
"/resume",
data,
);
return response.data;
};
export const useCreateResume = () => {
const {
error,
isPending: loading,
mutateAsync: createResumeFn,
} = useMutation({
mutationFn: createResume,
onSuccess: (data) => {
queryClient.setQueryData<ResumeDto>(["resume", { id: data.id }], data);
queryClient.setQueryData<ResumeDto[]>(["resumes"], (cache) => {
if (!cache) return [data];
return [...cache, data];
});
},
});
return { createResume: createResumeFn, loading, error };
};

View File

@ -0,0 +1,34 @@
import { DeleteResumeDto, ResumeDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
import { queryClient } from "@/client/libs/query-client";
export const deleteResume = async (data: DeleteResumeDto) => {
const response = await axios.delete<ResumeDto, AxiosResponse<ResumeDto>, DeleteResumeDto>(
`/resume/${data.id}`,
);
return response.data;
};
export const useDeleteResume = () => {
const {
error,
isPending: loading,
mutateAsync: deleteResumeFn,
} = useMutation({
mutationFn: deleteResume,
onSuccess: (data) => {
queryClient.removeQueries({ queryKey: ["resume", data.id] });
queryClient.setQueryData<ResumeDto[]>(["resumes"], (cache) => {
if (!cache) return [];
return cache.filter((resume) => resume.id !== data.id);
});
},
});
return { deleteResume: deleteResumeFn, loading, error };
};

View File

@ -0,0 +1,35 @@
import { ImportResumeDto, ResumeDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
import { queryClient } from "@/client/libs/query-client";
export const importResume = async (data: ImportResumeDto) => {
const response = await axios.post<ResumeDto, AxiosResponse<ResumeDto>, ImportResumeDto>(
"/resume/import",
data,
);
return response.data;
};
export const useImportResume = () => {
const {
error,
isPending: loading,
mutateAsync: importResumeFn,
} = useMutation({
mutationFn: importResume,
onSuccess: (data) => {
queryClient.setQueryData<ResumeDto>(["resume", { id: data.id }], data);
queryClient.setQueryData<ResumeDto[]>(["resumes"], (cache) => {
if (!cache) return [data];
return [...cache, data];
});
},
});
return { importResume: importResumeFn, loading, error };
};

View File

@ -0,0 +1,7 @@
export * from "./create";
export * from "./delete";
export * from "./print";
export * from "./resume";
export * from "./resumes";
export * from "./statistics";
export * from "./update";

View File

@ -0,0 +1,24 @@
import { UrlDto } from "@reactive-resume/dto";
import { useQuery } from "@tanstack/react-query";
import { RESUME_PREVIEW_KEY } from "@/client/constants/query-keys";
import { axios } from "@/client/libs/axios";
export const previewResume = async (data: { id: string }) => {
const response = await axios.get<UrlDto>(`/resume/print/${data.id}/preview`);
return response.data;
};
export const useResumePreview = (id: string) => {
const {
error,
isPending: loading,
data,
} = useQuery({
queryKey: [RESUME_PREVIEW_KEY, { id }],
queryFn: () => previewResume({ id }),
});
return { url: data?.url, loading, error };
};

View File

@ -0,0 +1,48 @@
import { StatisticsDto, UrlDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosError } from "axios";
import { RESUME_KEY } from "@/client/constants/query-keys";
import { toast } from "@/client/hooks/use-toast";
import { axios } from "@/client/libs/axios";
import { queryClient } from "@/client/libs/query-client";
export const printResume = async (data: { id: string }) => {
const response = await axios.get<UrlDto>(`/resume/print/${data.id}`);
return response.data;
};
export const usePrintResume = () => {
const {
error,
isPending: loading,
mutateAsync: printResumeFn,
} = useMutation({
mutationFn: printResume,
onSuccess: (_, { id }) => {
queryClient.setQueryData([...RESUME_KEY, "statistics", id], (cache: StatisticsDto) => {
if (cache === undefined) return cache;
return { ...cache, downloads: cache.downloads + 1 } satisfies StatisticsDto;
});
toast({
variant: "success",
title: "A PDF of your resume has been successfully generated.",
});
},
onError: (error) => {
if (error instanceof AxiosError) {
const message = error.response?.data.message || error.message;
toast({
variant: "error",
title: "An error occurred while trying to generate your resume.",
description: message,
});
}
},
});
return { printResume: printResumeFn, loading, error };
};

View File

@ -0,0 +1,34 @@
import { ResumeDto } from "@reactive-resume/dto";
import { useQuery } from "@tanstack/react-query";
import { RESUME_KEY } from "@/client/constants/query-keys";
import { axios } from "@/client/libs/axios";
import { useResumeStore } from "@/client/stores/resume";
export const findResumeById = async (data: { id: string }) => {
const response = await axios.get<ResumeDto>(`/resume/${data.id}`);
return response.data;
};
export const findResumeByUsernameSlug = async (data: { username: string; slug: string }) => {
const response = await axios.get<ResumeDto>(`/resume/public/${data.username}/${data.slug}`);
return response.data;
};
export const useResume = (id: string) => {
const {
error,
isPending: loading,
data: resume,
} = useQuery({
queryKey: [RESUME_KEY, { id }],
queryFn: () => findResumeById({ id }),
});
useResumeStore.setState({ resume });
useResumeStore.temporal.getState().clear();
return { resume, loading, error };
};

View File

@ -0,0 +1,25 @@
import { ResumeDto } from "@reactive-resume/dto";
import { useQuery } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { RESUMES_KEY } from "@/client/constants/query-keys";
import { axios } from "@/client/libs/axios";
export const fetchResumes = async () => {
const response = await axios.get<ResumeDto[], AxiosResponse<ResumeDto[]>>("/resume");
return response.data;
};
export const useResumes = () => {
const {
error,
isPending: loading,
data: resumes,
} = useQuery({
queryKey: RESUMES_KEY,
queryFn: fetchResumes,
});
return { resumes, loading, error };
};

View File

@ -0,0 +1,25 @@
import { StatisticsDto } from "@reactive-resume/dto";
import { useQuery } from "@tanstack/react-query";
import { RESUME_KEY } from "@/client/constants/query-keys";
import { axios } from "@/client/libs/axios";
export const findResumeStatisticsById = async (data: { id: string }) => {
const response = await axios.get<StatisticsDto>(`/resume/${data.id}/statistics`);
return response.data;
};
export const useResumeStatistics = (id: string, enabled: boolean = false) => {
const {
error,
isPending: loading,
data: statistics,
} = useQuery({
queryKey: [...RESUME_KEY, "statistics", id],
queryFn: () => findResumeStatisticsById({ id }),
enabled,
});
return { statistics, loading, error };
};

View File

@ -0,0 +1,51 @@
import { ResumeDto, UpdateResumeDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import debounce from "lodash.debounce";
import { axios } from "@/client/libs/axios";
import { queryClient } from "@/client/libs/query-client";
export const updateResume = async (data: UpdateResumeDto) => {
const response = await axios.patch<ResumeDto, AxiosResponse<ResumeDto>, UpdateResumeDto>(
`/resume/${data.id}`,
data,
);
queryClient.setQueryData<ResumeDto>(["resume", { id: response.data.id }], response.data);
queryClient.setQueryData<ResumeDto[]>(["resumes"], (cache) => {
if (!cache) return [response.data];
return cache.map((resume) => {
if (resume.id === response.data.id) return response.data;
return resume;
});
});
return response.data;
};
export const debouncedUpdateResume = debounce(updateResume, 500);
export const useUpdateResume = () => {
const {
error,
isPending: loading,
mutateAsync: updateResumeFn,
} = useMutation({
mutationFn: updateResume,
onSuccess: (data) => {
queryClient.setQueryData<ResumeDto>(["resume", { id: data.id }], data);
queryClient.setQueryData<ResumeDto[]>(["resumes"], (cache) => {
if (!cache) return [data];
return cache.map((resume) => {
if (resume.id === data.id) return data;
return resume;
});
});
},
});
return { updateResume: updateResumeFn, loading, error };
};

View File

@ -0,0 +1 @@
export * from "./upload-image";

View File

@ -0,0 +1,25 @@
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
export const uploadImage = (file: File) => {
const formData = new FormData();
formData.append("file", file);
return axios.put<string, AxiosResponse<string>, FormData>("/storage/image", formData, {
headers: { "Content-Type": "multipart/form-data" },
});
};
export const useUploadImage = () => {
const {
error,
isPending: loading,
mutateAsync: uploadImageFn,
} = useMutation({
mutationFn: uploadImage,
});
return { uploadImage: uploadImageFn, loading, error };
};

View File

@ -0,0 +1,27 @@
import { MessageDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
import { queryClient } from "@/client/libs/query-client";
export const deleteUser = async () => {
const response = await axios.delete<MessageDto, AxiosResponse<MessageDto>>("/user/me");
return response.data;
};
export const useDeleteUser = () => {
const {
error,
isPending: loading,
mutateAsync: deleteUserFn,
} = useMutation({
mutationFn: deleteUser,
onSuccess: () => {
queryClient.clear();
},
});
return { deleteUser: deleteUserFn, loading, error };
};

View File

@ -0,0 +1,3 @@
export * from "./delete-user";
export * from "./update-user";
export * from "./user";

View File

@ -0,0 +1,30 @@
import { UpdateUserDto, UserDto } from "@reactive-resume/dto";
import { useMutation } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { axios } from "@/client/libs/axios";
import { queryClient } from "@/client/libs/query-client";
export const updateUser = async (data: UpdateUserDto) => {
const response = await axios.patch<UserDto, AxiosResponse<UserDto>, UpdateUserDto>(
"/user/me",
data,
);
return response.data;
};
export const useUpdateUser = () => {
const {
error,
isPending: loading,
mutateAsync: updateUserFn,
} = useMutation({
mutationFn: updateUser,
onSuccess: (data) => {
queryClient.setQueryData(["user"], data);
},
});
return { updateUser: updateUserFn, loading, error };
};

View File

@ -0,0 +1,32 @@
import { UserDto } from "@reactive-resume/dto";
import { useQuery } from "@tanstack/react-query";
import { AxiosResponse } from "axios";
import { useEffect } from "react";
import { axios } from "@/client/libs/axios";
import { useAuthStore } from "@/client/stores/auth";
export const fetchUser = async () => {
const response = await axios.get<UserDto, AxiosResponse<UserDto>>("/user/me");
return response.data;
};
export const useUser = () => {
const setUser = useAuthStore((state) => state.setUser);
const {
error,
isPending: loading,
data: user,
} = useQuery({
queryKey: ["user"],
queryFn: fetchUser,
});
useEffect(() => {
setUser(user ? user : null);
}, [user, setUser]);
return { user: user, loading, error };
};