Added stop signal to not let the request happen twice
This commit is contained in:
parent
a2485d1797
commit
73511c72ca
5 changed files with 120 additions and 76 deletions
|
|
@ -365,8 +365,21 @@ export async function uploadFile(
|
||||||
return await api.post(`${BASE_URL_API}files/upload/${id}`, formData);
|
return await api.post(`${BASE_URL_API}files/upload/${id}`, formData);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getProfilePictures(): Promise<ProfilePicturesTypeAPI> {
|
export async function getProfilePictures(
|
||||||
return api.get(`${BASE_URL_API}files/list/profile_pictures`);
|
abortSignal,
|
||||||
|
): Promise<ProfilePicturesTypeAPI | null> {
|
||||||
|
try {
|
||||||
|
const res = await api.get(`${BASE_URL_API}images/list/profile_pictures`, {
|
||||||
|
signal: abortSignal,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function postCustomComponent(
|
export async function postCustomComponent(
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,12 @@ import { PROFILE_PICTURES_GET_ERROR_ALERT } from "../../../../../../../../../con
|
||||||
import { getProfilePictures } from "../../../../../../../../../controllers/API";
|
import { getProfilePictures } from "../../../../../../../../../controllers/API";
|
||||||
|
|
||||||
const useGetProfilePictures = (setErrorData) => {
|
const useGetProfilePictures = (setErrorData) => {
|
||||||
const handleGetProfilePictures = async () => {
|
const handleGetProfilePictures = async (abortSignal) => {
|
||||||
try {
|
try {
|
||||||
const profilePictures = await getProfilePictures();
|
const profilePictures = await getProfilePictures(abortSignal);
|
||||||
return profilePictures.files;
|
return profilePictures!.files;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
setErrorData({
|
setErrorData({
|
||||||
title: PROFILE_PICTURES_GET_ERROR_ALERT,
|
title: PROFILE_PICTURES_GET_ERROR_ALERT,
|
||||||
list: [(error as any)?.response?.data?.detail],
|
list: [(error as any)?.response?.data?.detail],
|
||||||
|
|
@ -16,7 +17,7 @@ const useGetProfilePictures = (setErrorData) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return handleGetProfilePictures;
|
return { handleGetProfilePictures };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useGetProfilePictures;
|
export default useGetProfilePictures;
|
||||||
|
|
|
||||||
|
|
@ -11,48 +11,31 @@ import HorizontalScrollFadeComponent from "../../../../../../../../components/ho
|
||||||
import LoadingComponent from "../../../../../../../../components/loadingComponent";
|
import LoadingComponent from "../../../../../../../../components/loadingComponent";
|
||||||
import Loading from "../../../../../../../../components/ui/loading";
|
import Loading from "../../../../../../../../components/ui/loading";
|
||||||
|
|
||||||
export default function ProfilePictureChooserComponent({ value, onChange }) {
|
type ProfilePictureChooserComponentProps = {
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
profilePictures: { [key: string]: string[] };
|
||||||
const getProfilePictures = useGetProfilePictures({ setErrorData });
|
loading: boolean;
|
||||||
|
value: string;
|
||||||
const [profilePictures, setProfilePictures] = useState<string[][]>([]);
|
onChange: (value: string) => void;
|
||||||
const [loading, setLoading] = useState(true);
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getProfilePictures()
|
|
||||||
.then((data) => {
|
|
||||||
if (data) {
|
|
||||||
data.forEach((profile_picture) => {
|
|
||||||
const [folder, path] = profile_picture.split("/");
|
|
||||||
setProfilePictures((prev) => {
|
|
||||||
if (prev[folder]) {
|
|
||||||
prev[folder].push(path);
|
|
||||||
} else {
|
|
||||||
prev[folder] = [path];
|
|
||||||
}
|
|
||||||
return prev;
|
|
||||||
});
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
export default function ProfilePictureChooserComponent({
|
||||||
|
profilePictures,
|
||||||
|
loading,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
}: ProfilePictureChooserComponentProps) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col justify-center gap-2">
|
<div className="flex flex-col justify-center gap-2">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Loading />
|
<Loading />
|
||||||
) : (
|
) : (
|
||||||
profilePictures.map((folder, idx) => (
|
Object.keys(profilePictures).map((folder, idx) => (
|
||||||
<Label>
|
<Label>
|
||||||
<div className="edit-flow-arrangement">
|
<div className="edit-flow-arrangement">
|
||||||
<span className="font-medium">{folder}</span>
|
<span className="font-medium">{folder}</span>
|
||||||
</div>
|
</div>
|
||||||
<HorizontalScrollFadeComponent>
|
<HorizontalScrollFadeComponent>
|
||||||
{folder.map((path, idx) => (
|
{profilePictures[folder].map((path, idx) => (
|
||||||
<img
|
<img
|
||||||
key={idx}
|
key={idx}
|
||||||
src={`${BACKEND_URL.slice(
|
src={`${BACKEND_URL.slice(
|
||||||
|
|
|
||||||
|
|
@ -10,59 +10,102 @@ import {
|
||||||
} from "../../../../../../components/ui/card";
|
} from "../../../../../../components/ui/card";
|
||||||
import { gradients } from "../../../../../../utils/styleUtils";
|
import { gradients } from "../../../../../../utils/styleUtils";
|
||||||
import ProfilePictureChooserComponent from "./components/profilePictureChooserComponent";
|
import ProfilePictureChooserComponent from "./components/profilePictureChooserComponent";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { GenericAbortSignal } from "axios";
|
||||||
|
|
||||||
type ProfilePictureFormComponentProps = {
|
type ProfilePictureFormComponentProps = {
|
||||||
profilePicture: string;
|
profilePicture: string;
|
||||||
handleInput: (event: any) => void;
|
handleInput: (event: any) => void;
|
||||||
handlePatchProfilePicture: (gradient: string) => void;
|
handlePatchProfilePicture: (gradient: string) => void;
|
||||||
|
handleGetProfilePictures: (
|
||||||
|
abortSignal: GenericAbortSignal | undefined,
|
||||||
|
) => Promise<string[]>;
|
||||||
userData: any;
|
userData: any;
|
||||||
};
|
};
|
||||||
const ProfilePictureFormComponent = ({
|
const ProfilePictureFormComponent = ({
|
||||||
profilePicture,
|
profilePicture,
|
||||||
handleInput,
|
handleInput,
|
||||||
handlePatchProfilePicture,
|
handlePatchProfilePicture,
|
||||||
|
handleGetProfilePictures,
|
||||||
userData,
|
userData,
|
||||||
}: ProfilePictureFormComponentProps) => {
|
}: ProfilePictureFormComponentProps) => {
|
||||||
|
const [profilePictures, setProfilePictures] = useState<{
|
||||||
|
[key: string]: string[];
|
||||||
|
}>({});
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const abortController = new AbortController();
|
||||||
|
|
||||||
|
handleGetProfilePictures(abortController.signal)
|
||||||
|
.then((data) => {
|
||||||
|
if (data) {
|
||||||
|
data.forEach((profile_picture) => {
|
||||||
|
const [folder, path] = profile_picture.split("/");
|
||||||
|
setProfilePictures((prev) => {
|
||||||
|
if (prev[folder]) {
|
||||||
|
prev[folder].push(path);
|
||||||
|
} else {
|
||||||
|
prev[folder] = [path];
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
Abort the request as it isn't needed anymore, the component being
|
||||||
|
unmounted. It helps avoid, among other things, the well-known "can't
|
||||||
|
perform a React state update on an unmounted component" warning.
|
||||||
|
*/
|
||||||
|
return () => abortController.abort();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Form.Root
|
||||||
<Form.Root
|
onSubmit={(event) => {
|
||||||
onSubmit={(event) => {
|
handlePatchProfilePicture(profilePicture);
|
||||||
handlePatchProfilePicture(profilePicture);
|
event.preventDefault();
|
||||||
event.preventDefault();
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<Card x-chunk="dashboard-04-chunk-1">
|
||||||
<Card x-chunk="dashboard-04-chunk-1">
|
<CardHeader>
|
||||||
<CardHeader>
|
<CardTitle>Profile Picture</CardTitle>
|
||||||
<CardTitle>Profile Picture</CardTitle>
|
<CardDescription>
|
||||||
<CardDescription>
|
Choose the image that appears as your profile picture.
|
||||||
Choose the image that appears as your profile picture.
|
</CardDescription>
|
||||||
</CardDescription>
|
</CardHeader>
|
||||||
</CardHeader>
|
<CardContent>
|
||||||
<CardContent>
|
<div className="py-2">
|
||||||
<div className="py-2">
|
<ProfilePictureChooserComponent
|
||||||
<ProfilePictureChooserComponent
|
profilePictures={profilePictures}
|
||||||
value={
|
loading={loading}
|
||||||
profilePicture == ""
|
value={
|
||||||
? userData?.profile_image ??
|
profilePicture == ""
|
||||||
gradients[
|
? userData?.profile_image ??
|
||||||
parseInt(userData?.id ?? "", 30) % gradients.length
|
gradients[
|
||||||
]
|
parseInt(userData?.id ?? "", 30) % gradients.length
|
||||||
: profilePicture
|
]
|
||||||
}
|
: profilePicture
|
||||||
onChange={(value) => {
|
}
|
||||||
handleInput({ target: { name: "profilePicture", value } });
|
onChange={(value) => {
|
||||||
}}
|
handleInput({ target: { name: "profilePicture", value } });
|
||||||
/>
|
}}
|
||||||
</div>
|
/>
|
||||||
</CardContent>
|
</div>
|
||||||
<CardFooter className="border-t px-6 py-4">
|
</CardContent>
|
||||||
<Form.Submit asChild>
|
<CardFooter className="border-t px-6 py-4">
|
||||||
<Button type="submit">Save</Button>
|
<Form.Submit asChild>
|
||||||
</Form.Submit>
|
<Button type="submit">Save</Button>
|
||||||
</CardFooter>
|
</Form.Submit>
|
||||||
</Card>
|
</CardFooter>
|
||||||
</Form.Root>
|
</Card>
|
||||||
</>
|
</Form.Root>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default ProfilePictureFormComponent;
|
export default ProfilePictureFormComponent;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import GeneralPageHeaderComponent from "./components/GeneralPageHeader";
|
||||||
import PasswordFormComponent from "./components/PasswordForm";
|
import PasswordFormComponent from "./components/PasswordForm";
|
||||||
import ProfilePictureFormComponent from "./components/ProfilePictureForm";
|
import ProfilePictureFormComponent from "./components/ProfilePictureForm";
|
||||||
import StoreApiKeyFormComponent from "./components/StoreApiKeyForm";
|
import StoreApiKeyFormComponent from "./components/StoreApiKeyForm";
|
||||||
|
import useGetProfilePictures from "./components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-get-profile-pictures";
|
||||||
|
|
||||||
export default function GeneralPage() {
|
export default function GeneralPage() {
|
||||||
const setCurrentFlowId = useFlowsManagerStore(
|
const setCurrentFlowId = useFlowsManagerStore(
|
||||||
|
|
@ -50,6 +51,8 @@ export default function GeneralPage() {
|
||||||
setErrorData,
|
setErrorData,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { handleGetProfilePictures } = useGetProfilePictures(setErrorData);
|
||||||
|
|
||||||
const { handlePatchProfilePicture } = usePatchProfilePicture(
|
const { handlePatchProfilePicture } = usePatchProfilePicture(
|
||||||
setSuccessData,
|
setSuccessData,
|
||||||
setErrorData,
|
setErrorData,
|
||||||
|
|
@ -82,6 +85,7 @@ export default function GeneralPage() {
|
||||||
profilePicture={profilePicture}
|
profilePicture={profilePicture}
|
||||||
handleInput={handleInput}
|
handleInput={handleInput}
|
||||||
handlePatchProfilePicture={handlePatchProfilePicture}
|
handlePatchProfilePicture={handlePatchProfilePicture}
|
||||||
|
handleGetProfilePictures={handleGetProfilePictures}
|
||||||
userData={userData}
|
userData={userData}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue