From 8d75586f8b98c975f70f02a806fd2b40227f63bf Mon Sep 17 00:00:00 2001 From: Ryan Moon Date: Sun, 29 Mar 2026 16:14:08 -0500 Subject: [PATCH] Add store logo and app icon uploads to settings page AvatarUpload component now supports custom category and placeholder icon props. Settings page shows two upload circles: Store Logo (for PDFs/invoices, uses ImageIcon placeholder) and App Icon (for sidebar/ login, uses Building placeholder). Added 'company' to allowed file entity types. --- .../src/components/shared/avatar-upload.tsx | 15 +++++++++------ .../src/routes/_authenticated/settings.tsx | 18 ++++++++++++++++-- packages/backend/src/routes/v1/files.ts | 2 +- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/packages/admin/src/components/shared/avatar-upload.tsx b/packages/admin/src/components/shared/avatar-upload.tsx index 7e49046..6655649 100644 --- a/packages/admin/src/components/shared/avatar-upload.tsx +++ b/packages/admin/src/components/shared/avatar-upload.tsx @@ -23,9 +23,11 @@ function entityFilesOptions(entityType: string, entityId: string) { } interface AvatarUploadProps { - entityType: 'user' | 'member' + entityType: 'user' | 'member' | 'company' entityId: string size?: 'sm' | 'md' | 'lg' + category?: string + placeholderIcon?: React.ComponentType<{ className?: string }> } const sizeClasses = { @@ -40,16 +42,17 @@ const iconSizes = { lg: 'h-12 w-12', } -export function AvatarUpload({ entityType, entityId, size = 'lg' }: AvatarUploadProps) { +export function AvatarUpload({ entityType, entityId, size = 'lg', category = 'profile', placeholderIcon: PlaceholderIcon }: AvatarUploadProps) { const queryClient = useQueryClient() const token = useAuthStore((s) => s.token) const fileInputRef = useRef(null) const [uploading, setUploading] = useState(false) + const IconComponent = PlaceholderIcon ?? User const { data: filesData } = useQuery(entityFilesOptions(entityType, entityId)) - // Find profile image from files - const profileFile = filesData?.data?.find((f) => f.path.includes('/profile-')) + // Find image by category + const profileFile = filesData?.data?.find((f) => f.path.includes(`/${category}-`)) const imageUrl = profileFile ? `/v1/files/serve/${profileFile.path}` : null async function handleUpload(file: File) { @@ -59,7 +62,7 @@ export function AvatarUpload({ entityType, entityId, size = 'lg' }: AvatarUpload formData.append('file', file) formData.append('entityType', entityType) formData.append('entityId', entityId) - formData.append('category', 'profile') + formData.append('category', category) // Delete existing profile image first if (profileFile) { @@ -105,7 +108,7 @@ export function AvatarUpload({ entityType, entityId, size = 'lg' }: AvatarUpload className="h-full w-full object-cover" /> ) : ( - + )}