Skip to content

Wallet logo and cover image upload successfully but are never displayed anywhere #831

Description

@mahdi2ba

Summary

Customizing a wallet with a logo and a cover/hero image appears to work: the files upload to S3,
the URLs are saved to the database, and the Save succeeds. But neither image is ever shown to a
user anywhere in the app.

The feature is effectively write-only. The only place the logo reappears is the Customize form
itself, as a preview of what you already uploaded. The cover image is not rendered by any component
at all.

How to reproduce

  1. Log in and go to Wallet -> tap a wallet -> Customize
  2. Upload a logo image and a hero/cover image
  3. Tap Save. It succeeds and redirects to the wallet details page after ~2 seconds
  4. Look at the wallet details page — no logo, no cover image
  5. Go back to the wallet list — no logo
  6. Reopen Customize — no logo preview either (see note below)

Actual result
The images are stored but invisible everywhere a user would expect to see them.

Expected result
The logo should appear on the wallet list row and the wallet details page. The cover image should
appear as the banner/header on the wallet details page. Otherwise there is no reason to upload them.

Evidence that the upload and save genuinely work

Database row for the test wallet after saving:

logo_url = https://treetracker-dev-wal-images.s3.eu-central-1.amazonaws.com/_2026-09-09T18%3A28%3A16.916Z
cover_url = https://treetracker-dev-wal-images.s3.eu-central-1.amazonaws.com/_2026-09-09T18%3A28%3A15.772Z

Both URLs return HTTP 200, content-type image/png, 239911 bytes. So S3, the API and the database are
all fine — this is purely a missing rendering step in the frontend.

Root cause — two distinct problems

(a) The cover/hero image: the field name differs at every layer

Layer Name used
Database column (written on save) cover_url — WalletService.js:158
What GET /wallets returns nothingcover_url appears 0 times in WalletRepository.getAllWallets, in any of its three UNION branches
What the frontend reads cover_image_url — customize/page.tsx:58

So the cover image is saved under one name, never sent back by the API, and looked up by the
frontend under a third name. It can never display, anywhere, under any circumstances.

cover_url is also missing from packages/wallet/src/types/wallet.ts, which is likely how the
mismatch survived review.

(b) The logo: returned by the API, then thrown away by the hook

logo_url IS selected in all three branches of WalletRepository.getAllWallets, so it does arrive at
the browser. But packages/wallet/src/hooks/useGetWallets.ts:26-38 reshapes each wallet into a new
object and simply omits it:

setWallets(
  result.wallets.map((w: any) => ({
    id: w.id,
    name: w.name,
    about: w.about,
    display_name: w.display_name,
    created_at: ...,
    tokens_in_wallet: w.tokens_in_wallet,
  })),
);

There is no logo_url in that mapping, so every component downstream receives a wallet object that
has no logo field at all. This is why the Customize preview at customize/page.tsx:55-56

if (wallet.logo_url) { setLogoPreview(wallet.logo_url); }

never fires: wallet.logo_url is always undefined, regardless of what the API sent.

Confirmed manually: on a fresh browser tab with a healthy login and no reload involved, the logo
preview is still absent.

Suggested fix

  1. Add logo_url: w.logo_url to the mapping in useGetWallets.ts:26-38. This alone makes the
    Customize preview work again, and is a one-line change.
  2. Pick ONE name for the cover field and use it consistently across the database, the API response
    and the frontend. Add it to WalletRepository.getAllWallets (all three UNION branches), to the
    useGetWallets mapping, and to packages/wallet/src/types/wallet.ts.
  3. Render the logo as the wallet avatar in the wallet list row (WalletItem) and on the wallet
    details page header.
  4. Render the cover image as the banner on the wallet details page.
  5. Add a sensible fallback for wallets with no images so the layout does not shift.

Worth a quick sweep while in there: the same mapping also drops any other field the API returns,
so check nothing else needed downstream is being silently discarded.

Notes

  • Reproduces every time.
  • Not a data-loss bug: the images are safe in S3 and the URLs are in the database, so once the
    rendering is added, previously uploaded images will appear without re-uploading.
  • The 5MB/1MB upload-limit mismatch is a separate ticket.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions