259 lines
8.1 KiB
TypeScript
259 lines
8.1 KiB
TypeScript
import { PatchUserRequest, UserDocumentTypes, UserDocuments, UserSettingsFieldStatus, UserSettingsField, User } from "@root/model/user";
|
||
import { produce } from "immer";
|
||
import { create } from "zustand";
|
||
import { createJSONStorage, devtools, persist } from "zustand/middleware";
|
||
import { StringSchema, string } from "yup";
|
||
import { patchUser } from "@root/api/user";
|
||
import { UserAccount, UserAccountSettingsFieldStatus, UserName, VerificationStatus } from "@root/model/account";
|
||
import { patchUserAccount } from "@root/api/account";
|
||
|
||
|
||
interface UserStore {
|
||
userId: string | null;
|
||
user: User | null;
|
||
userAccount: UserAccount | null;
|
||
settingsFields: (
|
||
UserSettingsFieldStatus &
|
||
UserAccountSettingsFieldStatus &
|
||
{ hasError: boolean; }
|
||
);
|
||
verificationStatus: VerificationStatus;
|
||
verificationType: "juridical" | "nko";
|
||
isDocumentsDialogOpen: boolean;
|
||
dialogType: "juridical" | "nko";
|
||
documents: UserDocuments;
|
||
}
|
||
|
||
const defaultFieldValues = {
|
||
value: "",
|
||
error: null,
|
||
touched: false,
|
||
};
|
||
|
||
const defaultFields: UserStore["settingsFields"] = {
|
||
firstname: { ...defaultFieldValues },
|
||
secondname: { ...defaultFieldValues },
|
||
middlename: { ...defaultFieldValues },
|
||
orgname: { ...defaultFieldValues },
|
||
email: { ...defaultFieldValues },
|
||
phoneNumber: { ...defaultFieldValues },
|
||
password: { ...defaultFieldValues },
|
||
hasError: false,
|
||
};
|
||
|
||
const defaultDocument = {
|
||
file: null,
|
||
uploadedFileName: null,
|
||
imageSrc: null,
|
||
};
|
||
|
||
const initialState: UserStore = {
|
||
userId: null,
|
||
user: null,
|
||
userAccount: null,
|
||
settingsFields: { ...defaultFields },
|
||
verificationStatus: "notVerificated",
|
||
verificationType: "juridical",
|
||
isDocumentsDialogOpen: false,
|
||
dialogType: "juridical",
|
||
documents: {
|
||
"ИНН": { ...defaultDocument },
|
||
"Устав": { ...defaultDocument },
|
||
"Свидетельство о регистрации НКО": { ...defaultDocument },
|
||
}
|
||
};
|
||
|
||
export const useUserStore = create<UserStore>()(
|
||
persist(
|
||
devtools(
|
||
(set, get) => initialState,
|
||
{
|
||
name: "User store",
|
||
enabled: process.env.NODE_ENV === "development",
|
||
}
|
||
),
|
||
{
|
||
version: 2,
|
||
name: "user",
|
||
storage: createJSONStorage(() => localStorage),
|
||
partialize: state => ({
|
||
userId: state.userId,
|
||
user: state.user,
|
||
}),
|
||
migrate: (persistedState, version) => ({
|
||
...persistedState as UserStore,
|
||
user: null,
|
||
}),
|
||
}
|
||
)
|
||
);
|
||
|
||
export const setUserId = (userId: string | null) => useUserStore.setState({ userId });
|
||
|
||
export const setUser = (user: User) => useUserStore.setState(
|
||
produce<UserStore>(state => {
|
||
state.user = user;
|
||
|
||
state.settingsFields.email.value = user?.email ?? "";
|
||
state.settingsFields.phoneNumber.value = user?.phoneNumber ?? "";
|
||
state.settingsFields.password.value = "";
|
||
})
|
||
);
|
||
|
||
export const setUserAccount = (user: UserAccount) => useUserStore.setState(
|
||
produce<UserStore>(state => {
|
||
state.userAccount = user;
|
||
|
||
state.settingsFields.firstname.value = user?.name.firstname ?? "";
|
||
state.settingsFields.secondname.value = user?.name.secondname ?? "";
|
||
state.settingsFields.middlename.value = user?.name.middlename ?? "";
|
||
state.settingsFields.orgname.value = user?.name.orgname ?? "";
|
||
})
|
||
);
|
||
|
||
export const clearUserData = () => useUserStore.setState({ ...initialState });
|
||
|
||
export const openDocumentsDialog = (type: UserStore["dialogType"]) => useUserStore.setState(
|
||
produce<UserStore>(state => {
|
||
state.isDocumentsDialogOpen = true;
|
||
state.dialogType = type;
|
||
})
|
||
);
|
||
|
||
export const closeDocumentsDialog = () => useUserStore.setState(
|
||
produce<UserStore>(state => {
|
||
state.isDocumentsDialogOpen = false;
|
||
})
|
||
);
|
||
|
||
export const setDocument = (type: UserDocumentTypes, file: File | undefined) => useUserStore.setState(
|
||
produce<UserStore>(state => {
|
||
if (!file) {
|
||
state.documents[type] = { ...defaultDocument };
|
||
return;
|
||
}
|
||
|
||
let imageSrc: string | null = null;
|
||
|
||
try {
|
||
const src = state.documents[type].imageSrc;
|
||
if (src) URL.revokeObjectURL(src);
|
||
|
||
imageSrc = URL.createObjectURL(file);
|
||
} catch (error) {
|
||
console.log("Error creating object url", error);
|
||
}
|
||
|
||
state.documents[type] = {
|
||
file,
|
||
uploadedFileName: null,
|
||
imageSrc,
|
||
};
|
||
})
|
||
);
|
||
|
||
export const setUploadedDocument = (type: UserDocumentTypes, fileName: string, url: string) => useUserStore.setState(
|
||
produce<UserStore>(state => {
|
||
state.documents[type] = {
|
||
file: null,
|
||
uploadedFileName: fileName,
|
||
imageSrc: url,
|
||
};
|
||
})
|
||
);
|
||
|
||
export const sendDocuments = () => {
|
||
const state = useUserStore.getState();
|
||
const type = state.dialogType;
|
||
const documents = state.documents;
|
||
|
||
|
||
|
||
// const formData = new FormData();
|
||
// formData.append("file1", file1);
|
||
// formData.append("file2", file2);
|
||
|
||
// revoke on success
|
||
// Object.values(documents).map(document => document?.imageSrc).forEach(src => {
|
||
// if (src) URL.revokeObjectURL(src);
|
||
// });
|
||
|
||
// useUserStore.setState(produce<UserStore>(state => {
|
||
// state.isDocumentsDialogOpen = false;
|
||
// }));
|
||
};
|
||
|
||
export const setSettingsField = (
|
||
fieldName: UserSettingsField | keyof UserName,
|
||
value: string,
|
||
) => useUserStore.setState(
|
||
produce<UserStore>(state => {
|
||
if (!state.settingsFields) return;
|
||
|
||
let errorMessage: string | null = null;
|
||
|
||
try {
|
||
validators[fieldName].validateSync(value);
|
||
} catch (error: any) {
|
||
errorMessage = error.message;
|
||
}
|
||
|
||
state.settingsFields[fieldName].value = value || "";
|
||
state.settingsFields[fieldName].touched = true;
|
||
state.settingsFields[fieldName].error = errorMessage;
|
||
|
||
state.settingsFields.hasError = Object.values(state.settingsFields).reduce((acc: boolean, field) => {
|
||
if (typeof field == "boolean") return acc;
|
||
|
||
if (field.error !== null) return true;
|
||
return acc;
|
||
}, false);
|
||
})
|
||
);
|
||
|
||
export const sendUserData = async () => {
|
||
const state = useUserStore.getState();
|
||
if (!state.settingsFields) return;
|
||
|
||
const isPatchingUser =
|
||
state.settingsFields.email.touched ||
|
||
state.settingsFields.password.touched ||
|
||
state.settingsFields.phoneNumber.touched;
|
||
|
||
const isPatchingUserAccount =
|
||
state.settingsFields.firstname.touched ||
|
||
state.settingsFields.secondname.touched ||
|
||
state.settingsFields.middlename.touched ||
|
||
state.settingsFields.orgname.touched;
|
||
|
||
const userPayload: PatchUserRequest = {
|
||
email: state.settingsFields.email.value,
|
||
password: state.settingsFields.password.value,
|
||
phoneNumber: state.settingsFields.phoneNumber.value,
|
||
};
|
||
|
||
const userAccountPayload: UserName = {
|
||
firstname: state.settingsFields.firstname.value,
|
||
secondname: state.settingsFields.secondname.value,
|
||
middlename: state.settingsFields.middlename.value,
|
||
orgname: state.settingsFields.orgname.value,
|
||
};
|
||
|
||
const [user, userAccount] = await Promise.all([
|
||
isPatchingUser && patchUser(userPayload),
|
||
isPatchingUserAccount && patchUserAccount(userAccountPayload),
|
||
]);
|
||
|
||
// if (user) setUser(user);
|
||
// if (userAccount) setUserAccount(userAccount);
|
||
};
|
||
|
||
const validators: Record<UserSettingsField | keyof UserName, StringSchema> = {
|
||
email: string().email("Неверный email"),
|
||
phoneNumber: string().matches(/^[+\d|\d]*$/, "Неверный номер телефона").min(6, "Номер телефона должен содержать минимум 6 символов"),
|
||
password: string().min(8, "Минимум 8 символов").matches(/^[.,:;-_+\d\w]+$/, "Некорректные символы в пароле"),
|
||
firstname: string(),
|
||
secondname: string(),
|
||
middlename: string(),
|
||
orgname: string(),
|
||
}; |