Added stop signal to not let the request happen twice

This commit is contained in:
Lucas Oliveira 2024-06-07 18:17:39 -03:00
commit 73511c72ca
5 changed files with 120 additions and 76 deletions

View file

@ -365,8 +365,21 @@ export async function uploadFile(
return await api.post(`${BASE_URL_API}files/upload/${id}`, formData);
}
export async function getProfilePictures(): Promise<ProfilePicturesTypeAPI> {
return api.get(`${BASE_URL_API}files/list/profile_pictures`);
export async function getProfilePictures(
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(

View file

@ -3,11 +3,12 @@ import { PROFILE_PICTURES_GET_ERROR_ALERT } from "../../../../../../../../../con
import { getProfilePictures } from "../../../../../../../../../controllers/API";
const useGetProfilePictures = (setErrorData) => {
const handleGetProfilePictures = async () => {
const handleGetProfilePictures = async (abortSignal) => {
try {
const profilePictures = await getProfilePictures();
return profilePictures.files;
const profilePictures = await getProfilePictures(abortSignal);
return profilePictures!.files;
} catch (error) {
console.log(error);
setErrorData({
title: PROFILE_PICTURES_GET_ERROR_ALERT,
list: [(error as any)?.response?.data?.detail],
@ -16,7 +17,7 @@ const useGetProfilePictures = (setErrorData) => {
}
};
return handleGetProfilePictures;
return { handleGetProfilePictures };
};
export default useGetProfilePictures;

View file

@ -11,48 +11,31 @@ import HorizontalScrollFadeComponent from "../../../../../../../../components/ho
import LoadingComponent from "../../../../../../../../components/loadingComponent";
import Loading from "../../../../../../../../components/ui/loading";
export default function ProfilePictureChooserComponent({ value, onChange }) {
const setErrorData = useAlertStore((state) => state.setErrorData);
const getProfilePictures = useGetProfilePictures({ setErrorData });
const [profilePictures, setProfilePictures] = useState<string[][]>([]);
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);
});
});
type ProfilePictureChooserComponentProps = {
profilePictures: { [key: string]: string[] };
loading: boolean;
value: string;
onChange: (value: string) => void;
};
export default function ProfilePictureChooserComponent({
profilePictures,
loading,
value,
onChange,
}: ProfilePictureChooserComponentProps) {
return (
<div className="flex flex-col justify-center gap-2">
{loading ? (
<Loading />
) : (
profilePictures.map((folder, idx) => (
Object.keys(profilePictures).map((folder, idx) => (
<Label>
<div className="edit-flow-arrangement">
<span className="font-medium">{folder}</span>
</div>
<HorizontalScrollFadeComponent>
{folder.map((path, idx) => (
{profilePictures[folder].map((path, idx) => (
<img
key={idx}
src={`${BACKEND_URL.slice(

View file

@ -10,59 +10,102 @@ import {
} from "../../../../../../components/ui/card";
import { gradients } from "../../../../../../utils/styleUtils";
import ProfilePictureChooserComponent from "./components/profilePictureChooserComponent";
import { useEffect, useState } from "react";
import { GenericAbortSignal } from "axios";
type ProfilePictureFormComponentProps = {
profilePicture: string;
handleInput: (event: any) => void;
handlePatchProfilePicture: (gradient: string) => void;
handleGetProfilePictures: (
abortSignal: GenericAbortSignal | undefined,
) => Promise<string[]>;
userData: any;
};
const ProfilePictureFormComponent = ({
profilePicture,
handleInput,
handlePatchProfilePicture,
handleGetProfilePictures,
userData,
}: 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 (
<>
<Form.Root
onSubmit={(event) => {
handlePatchProfilePicture(profilePicture);
event.preventDefault();
}}
>
<Card x-chunk="dashboard-04-chunk-1">
<CardHeader>
<CardTitle>Profile Picture</CardTitle>
<CardDescription>
Choose the image that appears as your profile picture.
</CardDescription>
</CardHeader>
<CardContent>
<div className="py-2">
<ProfilePictureChooserComponent
value={
profilePicture == ""
? userData?.profile_image ??
gradients[
parseInt(userData?.id ?? "", 30) % gradients.length
]
: profilePicture
}
onChange={(value) => {
handleInput({ target: { name: "profilePicture", value } });
}}
/>
</div>
</CardContent>
<CardFooter className="border-t px-6 py-4">
<Form.Submit asChild>
<Button type="submit">Save</Button>
</Form.Submit>
</CardFooter>
</Card>
</Form.Root>
</>
<Form.Root
onSubmit={(event) => {
handlePatchProfilePicture(profilePicture);
event.preventDefault();
}}
>
<Card x-chunk="dashboard-04-chunk-1">
<CardHeader>
<CardTitle>Profile Picture</CardTitle>
<CardDescription>
Choose the image that appears as your profile picture.
</CardDescription>
</CardHeader>
<CardContent>
<div className="py-2">
<ProfilePictureChooserComponent
profilePictures={profilePictures}
loading={loading}
value={
profilePicture == ""
? userData?.profile_image ??
gradients[
parseInt(userData?.id ?? "", 30) % gradients.length
]
: profilePicture
}
onChange={(value) => {
handleInput({ target: { name: "profilePicture", value } });
}}
/>
</div>
</CardContent>
<CardFooter className="border-t px-6 py-4">
<Form.Submit asChild>
<Button type="submit">Save</Button>
</Form.Submit>
</CardFooter>
</Card>
</Form.Root>
);
};
export default ProfilePictureFormComponent;

View file

@ -17,6 +17,7 @@ import GeneralPageHeaderComponent from "./components/GeneralPageHeader";
import PasswordFormComponent from "./components/PasswordForm";
import ProfilePictureFormComponent from "./components/ProfilePictureForm";
import StoreApiKeyFormComponent from "./components/StoreApiKeyForm";
import useGetProfilePictures from "./components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-get-profile-pictures";
export default function GeneralPage() {
const setCurrentFlowId = useFlowsManagerStore(
@ -50,6 +51,8 @@ export default function GeneralPage() {
setErrorData,
);
const { handleGetProfilePictures } = useGetProfilePictures(setErrorData);
const { handlePatchProfilePicture } = usePatchProfilePicture(
setSuccessData,
setErrorData,
@ -82,6 +85,7 @@ export default function GeneralPage() {
profilePicture={profilePicture}
handleInput={handleInput}
handlePatchProfilePicture={handlePatchProfilePicture}
handleGetProfilePictures={handleGetProfilePictures}
userData={userData}
/>