forked from OurHike/OurHike
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontributionFlow.ts
More file actions
67 lines (60 loc) · 2.42 KB
/
Copy pathcontributionFlow.ts
File metadata and controls
67 lines (60 loc) · 2.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// The first-contribution flow (WIREFRAMES.md §6).
//
// "The report is written and saved first; then Google / Apple / email, then
// trail name + reporter type." The ordering is the design, not a detail.
//
// Picture the actual moment: someone is standing at a blowdown with one bar,
// they have written down what they saw, and the app responds by sending them
// off to authenticate with Google. If that round trip fails - and on a ridge
// it often will - they can end up with neither an account nor their report.
// Saving to the outbox before authentication is ever mentioned means the
// worst case is an unsent report instead of a lost one.
//
// Sign-in is asked here rather than during onboarding because contributing is
// the first thing that genuinely needs an identity. Reading the map never
// does, and asking up front would put an account between someone and a map
// they have not yet been given a reason to trust.
import { enqueue, type OutboxItem, type ReportDraft } from './outbox'
export interface ContributionState {
hasAccount: boolean
/** Whether a trail name and reporter type have been set. */
hasIdentity: boolean
}
export type ContributionStep = 'sign-in' | 'identity' | 'send'
/**
* Saves the report. Always the first thing that happens, before any question
* about who the contributor is.
*/
export async function beginContribution(
draft: ReportDraft,
authoredAt: Date,
): Promise<OutboxItem> {
return enqueue(draft, authoredAt)
}
export function stepAfterSaving({
hasAccount,
hasIdentity,
}: ContributionState): ContributionStep {
// Account before identity, always: a trail name belongs to a profile, so
// asking for one first would mean collecting something with nowhere to put
// it.
if (!hasAccount) return 'sign-in'
if (!hasIdentity) return 'identity'
return 'send'
}
export interface ReporterTypeOption {
id: ReportDraft['reporter_type']
label: string
/**
* True where the claim only means something once a club confirms it.
* Anyone may select maintainer; it simply stays unverified until then,
* which is what stops it being a self-assigned badge.
*/
clubGranted: boolean
}
export const REPORTER_TYPES: ReporterTypeOption[] = [
{ id: 'thru', label: 'Thru-hiker', clubGranted: false },
{ id: 'section', label: 'Section hiker', clubGranted: false },
{ id: 'day', label: 'Day hiker', clubGranted: false },
{ id: 'maintainer', label: 'Maintainer', clubGranted: true },
]