Skip to content

wire up photo upload on donation details submission (REP-49) - #33

Closed
stephenhungg wants to merge 2 commits into
stephenhung/rep-41-connect-my-tasks-detailsfrom
stephenhung/rep-49-photo-upload-mobile
Closed

wire up photo upload on donation details submission (REP-49)#33
stephenhungg wants to merge 2 commits into
stephenhung/rep-41-connect-my-tasks-detailsfrom
stephenhung/rep-49-photo-upload-mobile

Conversation

@stephenhungg

Copy link
Copy Markdown
Contributor

Summary

Closes REP-49 on the mobile side. Captures the selected photo URI in state and sends it through the completion endpoint as multipart/form-data. Pairs with backend PR replate/replate-business#2803 which adds the Paperclip attachment on Task.

Changes

src/app/donation-details/[id].tsx

  • New photoUri state (string | null), wired into PhotoUpload.onSelect={setPhotoUri} (was a no-op before).
  • handleComplete passes photoUri into submitCompletionDetails.

api/config.ts

  • submitCompletionDetails now accepts optional photoUri. When present, it switches from JSON to FormData:
    • Fields sent as task[total_pounds_entered], task[description], task[photo] because the backend's wrap_parameters is JSON-only, so keys need to be pre-wrapped for multipart to land under params["task"][...].
    • Photo appended as {uri, name, type} — React Native's FormData convention for file uploads. Filename and mime inferred from the expo-image-picker URI (defaults to image/jpeg, switches to image/png on .png).
    • Content-Type header is intentionally omitted so fetch sets it to multipart/form-data; boundary=... automatically — setting it manually breaks the boundary.
  • When no photo: falls through to the original JSON path, unchanged behavior.

Base branch

Targeting stephenhung/rep-41-connect-my-tasks-details because the issue's dev workflow says to branch off the previous sprint's branch. This is a stacked PR — REP-41 should land first, then this rebases onto design-system-overhaul (or main depending on how REP-41 gets merged).

Notes / flags

  • apiRequest calls response.json() on a 204 No Content response — the endpoint returns head 204, which will make response.json() throw on an empty body. This is a latent bug from before REP-49, not something this PR introduces. The error gets swallowed by the try/catch in handleComplete, so the user still sees "Donation recorded!" and the redirect fires. Worth fixing in a follow-up.
  • FormData typing: RN's FormData.append accepts {uri, name, type} file objects, but TypeScript's DOM types only accept Blob | string. Used as unknown as Blob which is the standard workaround.

Test plan

  • pnpm tsc clean
  • pnpm lint:check clean
  • pnpm prettier:check clean
  • husky pre-commit hook passed
  • Not manually tested — see below
  • Select photo → tap Complete → confirm Task.last.photo_file_name populates in Rails console (requires backend PR #2803 deployed)
  • Submit without a photo → confirm JSON path still works end-to-end

Testing status — heads up

I did NOT manually run the app to test this end-to-end. All that was verified is static analysis: TypeScript, ESLint, Prettier, and the husky pre-commit hook — all clean. The backend + mobile need to be deployed together and poked manually (the issue's check step uses Rails console + Task.last.photo_file_name).

🤖 Generated with Claude Code

Capture the PhotoUpload component's selected URI in local state and
pass it through submitCompletionDetails. When a photo is present the
request is sent as multipart/form-data with task[...] field namespacing
(wrap_parameters is JSON-only on the backend, so keys need to be
pre-wrapped for multipart). Content-Type is intentionally not set so
fetch can fill in the multipart boundary automatically.

Closes REP-49
CI's pnpm install --frozen-lockfile was failing across PRs #30, #32,
#33 because pnpm-lock.yaml had react-native-svg pinned at ^15.15.3 but
package.json says 15.12.1. Regenerated the lockfile so the specifier
matches. Drift is pre-existing on the design-system-overhaul branch
and just propagated up the stack.
stephenhungg added a commit that referenced this pull request Apr 10, 2026
CI's pnpm install --frozen-lockfile was failing across PRs #30, #32,
#33 because pnpm-lock.yaml had react-native-svg pinned at ^15.15.3 but
package.json says 15.12.1. Regenerated the lockfile so the specifier
matches. Drift is pre-existing on the design-system-overhaul branch
and just propagated up the stack.
@stephenhungg

Copy link
Copy Markdown
Contributor Author

Superseded by #34, which rebuilds REP-49 (mobile side) directly off main without the design-system-overhaul + REP-41 stack. Branch stays alive for now as a fallback until #34 has been manually verified on a device.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant