Fix organization logo update

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-10-15 10:13:18 +02:00
parent b188e73ded
commit bd7351f0ed

View File

@@ -262,6 +262,10 @@ export default function SettingsPage({ queryRef }: Props) {
const memberships = membershipsPagination.data.memberships?.edges.map((edge) => edge.node) || []; const memberships = membershipsPagination.data.memberships?.edges.map((edge) => edge.node) || [];
const invitations = invitationsPagination.data.invitations?.edges.map((edge) => edge.node) || []; const invitations = invitationsPagination.data.invitations?.edges.map((edge) => edge.node) || [];
const [activeTab, setActiveTab] = useState<"memberships" | "invitations">("memberships"); const [activeTab, setActiveTab] = useState<"memberships" | "invitations">("memberships");
const [logoFile, setLogoFile] = useState<File | null>(null);
const [horizontalLogoFile, setHorizontalLogoFile] = useState<File | null>(null);
const [logoPreview, setLogoPreview] = useState<string | null>(null);
const [horizontalLogoPreview, setHorizontalLogoPreview] = useState<string | null>(null);
const { formState, handleSubmit, register, reset } = useFormWithSchema( const { formState, handleSubmit, register, reset } = useFormWithSchema(
organizationSchema, organizationSchema,
@@ -284,20 +288,37 @@ export default function SettingsPage({ queryRef }: Props) {
email: organization.email || "", email: organization.email || "",
headquarterAddress: organization.headquarterAddress || "", headquarterAddress: organization.headquarterAddress || "",
}); });
setLogoFile(null);
setHorizontalLogoFile(null);
setLogoPreview(null);
setHorizontalLogoPreview(null);
}, [organization, reset]); }, [organization, reset]);
const onSubmit = handleSubmit((data: OrganizationFormData) => { const onSubmit = handleSubmit((data: OrganizationFormData) => {
const uploadables: Record<string, File> = {};
if (logoFile) {
uploadables["input.logo"] = logoFile;
}
if (horizontalLogoFile) {
uploadables["input.horizontalLogoFile"] = horizontalLogoFile;
}
updateOrganization({ updateOrganization({
variables: { variables: {
input: { input: {
organizationId: organization.id, organizationId: organization.id,
name: data.name, name: data.name,
description: data.description || null, description: data.description || undefined,
websiteUrl: data.websiteUrl || null, websiteUrl: data.websiteUrl || undefined,
email: data.email || null, email: data.email || undefined,
headquarterAddress: data.headquarterAddress || null, headquarterAddress: data.headquarterAddress || undefined,
logo: logoFile ? null : undefined,
horizontalLogoFile: horizontalLogoFile ? null : undefined,
}, },
}, },
uploadables: Object.keys(uploadables).length > 0 ? uploadables : undefined,
onError() { onError() {
toast({ toast({
title: __("Error"), title: __("Error"),
@@ -317,68 +338,30 @@ export default function SettingsPage({ queryRef }: Props) {
}); });
}); });
const updateOrganizationLogo: ChangeEventHandler<HTMLInputElement> = (e) => { const handleLogoChange: ChangeEventHandler<HTMLInputElement> = (e) => {
const file = e.target.files?.[0]; const file = e.target.files?.[0];
if (!file) { if (!file) {
return; return;
} }
updateOrganization({ setLogoFile(file);
variables: { const reader = new FileReader();
input: { reader.onloadend = () => {
organizationId: organization.id, setLogoPreview(reader.result as string);
logo: null, };
}, reader.readAsDataURL(file);
},
uploadables: {
"input.logo": file,
},
onError() {
toast({
title: __("Error"),
description: __("Failed to update logo"),
variant: "error",
});
},
onCompleted() {
toast({
title: __("Success"),
description: __("Your organization logo has been updated successfully."),
variant: "success",
});
},
});
}; };
const updateHorizontalLogo: ChangeEventHandler<HTMLInputElement> = (e) => { const handleHorizontalLogoChange: ChangeEventHandler<HTMLInputElement> = (e) => {
const file = e.target.files?.[0]; const file = e.target.files?.[0];
if (!file) { if (!file) {
return; return;
} }
updateOrganization({ setHorizontalLogoFile(file);
variables: { const reader = new FileReader();
input: { reader.onloadend = () => {
organizationId: organization.id, setHorizontalLogoPreview(reader.result as string);
horizontalLogoFile: null, };
}, reader.readAsDataURL(file);
},
uploadables: {
"input.horizontalLogoFile": file,
},
onError() {
toast({
title: __("Error"),
description: __("Failed to update horizontal logo."),
variant: "error",
});
},
onCompleted() {
toast({
title: __("Success"),
description: __("Your organization horizontal logo has been updated successfully."),
variant: "success",
});
},
});
}; };
const deleteDialogRef = useDialogRef(); const deleteDialogRef = useDialogRef();
@@ -428,13 +411,13 @@ export default function SettingsPage({ queryRef }: Props) {
<Label>{__("Organization logo")}</Label> <Label>{__("Organization logo")}</Label>
<div className="flex w-max items-center gap-4"> <div className="flex w-max items-center gap-4">
<Avatar <Avatar
src={organization.logoUrl} src={logoPreview || organization.logoUrl}
name={organization.name} name={organization.name}
size="xl" size="xl"
/> />
<FileButton <FileButton
disabled={formState.isSubmitting} disabled={formState.isSubmitting}
onChange={updateOrganizationLogo} onChange={handleLogoChange}
variant="secondary" variant="secondary"
className="ml-auto" className="ml-auto"
accept="image/png,image/jpeg,image/jpg" accept="image/png,image/jpeg,image/jpg"
@@ -449,10 +432,10 @@ export default function SettingsPage({ queryRef }: Props) {
{__("Upload a horizontal version of your logo for use in documents")} {__("Upload a horizontal version of your logo for use in documents")}
</p> </p>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
{organization.horizontalLogoUrl && ( {(horizontalLogoPreview || organization.horizontalLogoUrl) && (
<div className="border border-border-solid rounded-md p-4 bg-surface-secondary"> <div className="border border-border-solid rounded-md p-4 bg-surface-secondary">
<img <img
src={organization.horizontalLogoUrl} src={horizontalLogoPreview || organization.horizontalLogoUrl || undefined}
alt={__("Horizontal logo")} alt={__("Horizontal logo")}
className="h-12 max-w-xs object-contain" className="h-12 max-w-xs object-contain"
/> />
@@ -460,17 +443,18 @@ export default function SettingsPage({ queryRef }: Props) {
)} )}
<FileButton <FileButton
disabled={formState.isSubmitting} disabled={formState.isSubmitting}
onChange={updateHorizontalLogo} onChange={handleHorizontalLogoChange}
variant="secondary" variant="secondary"
accept="image/png,image/jpeg,image/jpg" accept="image/png,image/jpeg,image/jpg"
> >
{organization.horizontalLogoUrl ? __("Change horizontal logo") : __("Upload horizontal logo")} {(horizontalLogoPreview || organization.horizontalLogoUrl) ? __("Change horizontal logo") : __("Upload horizontal logo")}
</FileButton> </FileButton>
{organization.horizontalLogoUrl && ( {(organization.horizontalLogoUrl && !horizontalLogoFile) && (
<Dialog <Dialog
ref={deleteDialogRef} ref={deleteDialogRef}
trigger={ trigger={
<Button <Button
type="button"
variant="quaternary" variant="quaternary"
icon={IconTrashCan} icon={IconTrashCan}
aria-label={__("Delete horizontal logo")} aria-label={__("Delete horizontal logo")}
@@ -549,7 +533,7 @@ export default function SettingsPage({ queryRef }: Props) {
/> />
</div> </div>
{formState.isDirty && ( {(formState.isDirty || logoFile || horizontalLogoFile) && (
<div className="flex justify-end pt-6"> <div className="flex justify-end pt-6">
<Button type="submit" disabled={formState.isSubmitting}> <Button type="submit" disabled={formState.isSubmitting}>
{formState.isSubmitting {formState.isSubmitting