diff --git a/app/components/Profile/Profile.EditLoginModal.tsx b/app/components/Profile/Profile.EditLoginModal.tsx new file mode 100644 index 0000000..6239438 --- /dev/null +++ b/app/components/Profile/Profile.EditLoginModal.tsx @@ -0,0 +1,154 @@ +"use client"; + +import { Button, Modal, Textarea } from "flowbite-react"; +import { ENDPOINTS } from "#/api/config"; +import { useEffect, useState } from "react"; +import { useSWRConfig } from "swr"; +import { Spinner } from "../Spinner/Spinner"; +import { unixToDate } from "#/api/utils"; +import { useUserStore } from "#/store/auth"; + +export const ProfileEditLoginModal = (props: { + isOpen: boolean; + setIsOpen: (isOpen: boolean) => void; + token: string; + setLogin: (status: string) => void; + profile_id: number; +}) => { + const [loading, setLoading] = useState(false); + const [sending, setSending] = useState(false); + const [_login, _setLogin] = useState(""); + const [_loginData, _setLoginData] = useState({ + code: 0, + avatar: "", + login: "", + is_change_available: false, + last_change_at: 0, + next_change_available_at: 0, + }); + const [_loginLength, _setLoginLength] = useState(0); + const { mutate } = useSWRConfig(); + const userStore = useUserStore(); + + useEffect(() => { + setLoading(true); + fetch(`${ENDPOINTS.user.settings.login.info}?token=${props.token}`) + .then((res) => { + if (res.ok) { + return res.json(); + } + }) + .then((data) => { + _setLoginData(data); + _setLogin(data.login); + _setLoginLength(data.login.length); + setLoading(false); + }); + }, [props.isOpen]); + + function handleInput(e: any) { + _setLogin(e.target.value); + _setLoginLength(e.target.value.length); + } + + function _setLoginSetting() { + setSending(true); + if (!_login || _login == "") { + alert("Никнейм не может быть пустым"); + return; + } + fetch( + `${ENDPOINTS.user.settings.login.change}?login=${encodeURIComponent( + _login + )}&token=${props.token}` + ) + .then((res) => { + if (res.ok) { + return res.json(); + } else { + new Error("failed to send data"); + } + }) + .then((data) => { + if (data.code == 3) { + alert("Данный никнейм уже существует, попробуйте другой"); + setSending(false); + return; + } + + mutate( + `${ENDPOINTS.user.profile}/${props.profile_id}?token=${props.token}` + ); + userStore.checkAuth(); + props.setLogin(_login); + setSending(false); + props.setIsOpen(false); + }) + .catch((err) => { + console.log(err); + setSending(false); + }); + } + + return ( + <Modal + dismissible + show={props.isOpen} + onClose={() => props.setIsOpen(false)} + size={"4xl"} + > + <Modal.Header>Изменить никнейм</Modal.Header> + <Modal.Body> + {loading ? ( + <div className="flex items-center justify-center py-8"> + <Spinner /> + </div> + ) : ( + <> + {!_loginData.is_change_available ? ( + <> + <p>Вы недавно изменили никнейм</p> + <p> + следующее изменение будет доступно:{" "} + <span className="font-bold"> + {unixToDate(_loginData.next_change_available_at, "full")} + </span> + </p> + </> + ) : ( + <> + <Textarea + disabled={sending} + rows={1} + id="login" + className="w-full" + name="login" + onChange={(e) => handleInput(e)} + value={_login} + maxLength={20} + /> + <p className="text-sm text-right text-gray-500 dark:text-gray-300"> + {_loginLength}/20 + </p> + </> + )} + </> + )} + </Modal.Body> + <Modal.Footer> + {_loginData.is_change_available && ( + <Button + color="blue" + onClick={() => _setLoginSetting()} + disabled={sending || loading} + > + Сохранить + </Button> + )} + <Button color="red" onClick={() => props.setIsOpen(false)}> + Отмена + </Button> + </Modal.Footer> + </Modal> + ); +}; diff --git a/app/components/Profile/Profile.EditModal.tsx b/app/components/Profile/Profile.EditModal.tsx index bb0d7fc..a7af72e 100644 --- a/app/components/Profile/Profile.EditModal.tsx +++ b/app/components/Profile/Profile.EditModal.tsx @@ -12,6 +12,7 @@ import { ProfileEditSocialModal } from "./Profile.EditSocialModal"; import { CropModal } from "../CropModal/CropModal"; import { useSWRConfig } from "swr"; import { useUserStore } from "#/store/auth"; +import { ProfileEditLoginModal } from "./Profile.EditLoginModal"; const fetcher = async (url: string) => { const res = await fetch(url); @@ -37,6 +38,7 @@ export const ProfileEditModal = (props: { const [statusModalOpen, setStatusModalOpen] = useState(false); const [socialModalOpen, setSocialModalOpen] = useState(false); const [avatarModalOpen, setAvatarModalOpen] = useState(false); + const [loginModalOpen, setLoginModalOpen] = useState(false); const [avatarUri, setAvatarUri] = useState(null); const [tempAvatarUri, setTempAvatarUri] = useState(null); const [privacyModalSetting, setPrivacyModalSetting] = useState("none"); @@ -160,9 +162,6 @@ export const ProfileEditModal = (props: { <span className="w-8 h-8 iconify mdi--user"></span> <p className="text-xl font-bold">Профиль</p> </div> - <p className="mx-1 text-base text-gray-500"> - Некоторые изменения будут видны после перезагрузки страницы - </p> </div> <button className="p-2 text-left rounded-md hover:bg-gray-100" @@ -205,6 +204,9 @@ export const ProfileEditModal = (props: { <button className="p-2 text-left rounded-md hover:bg-gray-100" disabled={prefData.is_change_login_banned} + onClick={() => { + setLoginModalOpen(true); + }} > <p className="text-lg">Изменить никнейм</p> <p className="text-base text-gray-500"> @@ -366,7 +368,6 @@ export const ProfileEditModal = (props: { src={tempAvatarUri} setSrc={setAvatarUri} setTempSrc={setTempAvatarUri} - // setImageData={setImageData} aspectRatio={1 / 1} guides={true} quality={100} @@ -376,6 +377,13 @@ export const ProfileEditModal = (props: { width={600} height={600} /> + <ProfileEditLoginModal + isOpen={loginModalOpen} + setIsOpen={setLoginModalOpen} + token={props.token} + setLogin={setLogin} + profile_id={props.profile_id} + /> </> ); }; diff --git a/public/changelog/3.2.1.md b/public/changelog/3.2.1.md index da51a82..a6e062f 100644 --- a/public/changelog/3.2.1.md +++ b/public/changelog/3.2.1.md @@ -1,4 +1,8 @@ -# 3.2.0 +# 3.2.1 + +## Добавлено + +- Редактирование профиля ## Изменено