Tidy the header and Settings; remove a featured song
CI / check (push) Canceled after 0s

- Web header is just the logo and Feed / Profile / Settings (current page
  highlighted). On phones those move to a bottom tab bar. Log out, Admin
  and Support moved into Settings.
- The bottom of Settings (web and app) is now one Account list: email,
  password, blocked accounts, admin, support, privacy, terms, log out and
  delete, each a row that opens in place (web) or a screen (app).
- Featured song shows what's featured now, with Change and Remove.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
This commit is contained in:
2026-10-06 14:15:14 -04:00
co-authored by Claude Opus 5.5
parent 75062d3644
commit 601398acd6
6 changed files with 499 additions and 244 deletions
+34 -27
View File
@@ -17,7 +17,7 @@ import { FeaturedPicker } from '@/components/FeaturedPicker';
import { Screen } from '@/components/Screen';
import { ServiceName } from '@/components/ServiceName';
import { SharingControls } from '@/components/SharingControls';
import { Body, Button, Card, Chip, Field, Heading, Row, Title } from '@/components/ui';
import { Body, Button, Card, Chip, Field, Heading, ListRow, Row, Title } from '@/components/ui';
import { api } from '@/lib/api';
import { WEB_URL } from '@/lib/config';
import { showError } from '@/lib/errors';
@@ -451,35 +451,42 @@ function Account() {
},
},
]);
const email = () =>
Alert.alert(
me?.email ?? 'Email',
me?.pendingEmail
? `Changing to ${me.pendingEmail}: open the link we sent there.`
: me?.emailVerified
? 'Confirmed.'
: 'Not confirmed yet. Open the link we emailed you.',
[
{ text: 'Change email', onPress: () => router.push('/change-email') },
...(me?.pendingEmail
? [{ text: 'Cancel the change', onPress: cancelChange }]
: !me?.emailVerified
? [{ text: 'Send the link again', onPress: resend }]
: []),
{ text: 'Close', style: 'cancel' as const },
],
);
const confirmSignOut = () =>
Alert.alert('Log out?', undefined, [
{ text: 'Cancel', style: 'cancel' },
{ text: 'Log out', onPress: signOut },
]);
return (
<Card>
<Heading>Account</Heading>
<Body muted style={styles.small}>
<Card style={{ gap: 0 }}>
<Heading style={{ marginBottom: space.sm }}>Account</Heading>
<ListRow first label="Email" value={me?.emailVerified ? me.email : `${me?.email ?? ''} · not confirmed`} onPress={email} />
<ListRow label="Password" value="Change" onPress={() => router.push('/change-password')} />
<ListRow label="Blocked accounts" onPress={() => router.push('/blocked')} />
<ListRow label="Privacy policy" onPress={() => Linking.openURL(`${WEB_URL}/privacy`)} />
<ListRow label="Terms of use" onPress={() => Linking.openURL(`${WEB_URL}/terms`)} />
<ListRow label="Log out" onPress={confirmSignOut} />
<ListRow label="Delete account" danger onPress={confirmDelete} />
<Body muted style={[styles.small, { marginTop: space.sm }]}>
Signed in as @{me?.username}
</Body>
<Body style={styles.small}>
{me?.email} · {me?.emailVerified ? 'confirmed' : 'not confirmed'}
</Body>
{me?.pendingEmail ? (
<Body muted style={styles.small}>
Changing to {me.pendingEmail}: open the link we sent there.
</Body>
) : null}
<Row>
{me && !me.emailVerified && !me.pendingEmail && <Button small variant="primary" title="Resend confirmation" onPress={resend} />}
{me?.pendingEmail && <Button small title="Cancel email change" onPress={cancelChange} />}
<Button small title="Change email" onPress={() => router.push('/change-email')} />
<Button small title="Change password" onPress={() => router.push('/change-password')} />
</Row>
<Row>
<Button small title="Privacy policy" onPress={() => Linking.openURL(`${WEB_URL}/privacy`)} />
<Button small title="Terms" onPress={() => Linking.openURL(`${WEB_URL}/terms`)} />
</Row>
<Button small title="Blocked accounts" onPress={() => router.push('/blocked')} style={{ alignSelf: 'flex-start' }} />
<Row>
<Button small title="Log out" onPress={signOut} />
<Button small variant="danger" title="Delete account" onPress={confirmDelete} />
</Row>
</Card>
);
}