Skip to content

feat: AvatarUploader component (props-only, presentational) #134

Description

@I-am-nothing

Problem

Avatar upload UI will appear in web-account now and likely web-applications later. Per repo convention (separate PR per component), ship the shared component first with no runtime API coupling.

Scope

  • src/components/AvatarUploader/:
    • AvatarUploader.tsx: avatar circle, hover overlay (upload + remove buttons), file input, drag-drop
    • Props: currentUrl?: string, onUpload: (file: File) => Promise<string>, onRemove: () => Promise<void>, maxBytes?: number, acceptedMimes?: string[]
    • States: idle, uploading (spinner), success (flash + new image), error (toast hook)
    • Client-side validation: MIME and size (mirrors backend caps)
  • Storybook story with mocked async handlers (all states)
  • RTL tests: file accepted, file rejected (size), file rejected (mime), remove flow
  • Export from package barrel
  • A11y: keyboard-accessible buttons, alt text, aria-busy during upload

Out-of-scope

  • Cropping / dimension editing
  • Direct API calls (props-only contract — consumers wire I/O)

Acceptance criteria

  • Storybook story renders all states
  • RTL tests green
  • No dependency on api-client-auth
  • release label on merge publishes new version

Dependencies

None

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureNew feature or componentp1:highP1 — do this sprintsize:mMedium — ~1 day

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions