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.
This commit is contained in:
@@ -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<HTMLInputElement>(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"
|
||||
/>
|
||||
) : (
|
||||
<User className={`${iconSizes[size]} text-muted-foreground`} />
|
||||
<IconComponent className={`${iconSizes[size]} text-muted-foreground`} />
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Skeleton } from '@/components/ui/skeleton'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'
|
||||
import { AvatarUpload } from '@/components/shared/avatar-upload'
|
||||
import { Save, Plus, Trash2, MapPin, Building } from 'lucide-react'
|
||||
import { Save, Plus, Trash2, MapPin, Building, ImageIcon } from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
interface StoreSettings {
|
||||
@@ -132,7 +132,21 @@ function SettingsPage() {
|
||||
</div>
|
||||
)}
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<CardContent className="space-y-6">
|
||||
{/* Logo upload */}
|
||||
<div className="flex items-start gap-8">
|
||||
<div className="text-center space-y-2">
|
||||
<Label className="text-xs text-muted-foreground">Store Logo</Label>
|
||||
<AvatarUpload entityType="company" entityId={store.id} size="lg" category="logo" placeholderIcon={ImageIcon} />
|
||||
<p className="text-[10px] text-muted-foreground">Used on PDFs, invoices, receipts</p>
|
||||
</div>
|
||||
<div className="text-center space-y-2">
|
||||
<Label className="text-xs text-muted-foreground">App Icon</Label>
|
||||
<AvatarUpload entityType="company" entityId={store.id} size="md" category="icon" placeholderIcon={Building} />
|
||||
<p className="text-[10px] text-muted-foreground">Sidebar & login screen</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{editing ? (
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
|
||||
Reference in New Issue
Block a user