fix(client): contact-request endpoint path + search screen polish
1. Contact requests silently 404'd
fetchContactRequests hit /api/relay/contacts, but the server mounts
the whole /relay/* group at root (no /api prefix). Result: every
poll returned 404, the catch swallowed it, and the notifications
tab stayed empty even after the user sent themselves a CONTACT_
REQUEST on-chain. Fixed the client path to /relay/contacts — same
pattern as sendEnvelope / fetchInbox in the v1.0.x relay cleanup.
2. Search screen was half-finished
SearchBar used a dual-state hack (idle-centered Text overlaid with
an invisible TextInput) that broke focus + alignment on Android and
sometimes ate taps. Rewrote as a plain single-row pill: icon +
TextInput + optional clear button. Fewer moving parts, predictable
focus, proper placeholder styling.
new-contact.tsx cleaned up:
- Title "New chat" → "Поиск" (matches the NavBar tab label and the
rest of the Russian UI).
- All labels localised: "Accept/Decline", "Intro", "Anti-spam fee",
fee-tier names, error messages, final CTA.
- Proper empty-state hint when query is empty (icon + headline +
explanation of @username / hex / DC prefix) instead of just a
floating helper text.
- Search button hidden until user types something — the empty-
state stands alone, no dead grey button under it.
- onClear handler on SearchBar resets the resolved profile too.
requests.tsx localised: title, empty-state, Accept/Decline button
copy, confirmation Alert text.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -51,7 +51,7 @@ export default function RequestsScreen() {
|
||||
setRequests(requests.filter(r => r.txHash !== req.txHash));
|
||||
router.replace(`/(app)/chats/${req.from}` as never);
|
||||
} catch (e: any) {
|
||||
Alert.alert('Accept failed', humanizeTxError(e));
|
||||
Alert.alert('Не удалось принять', humanizeTxError(e));
|
||||
} finally {
|
||||
setAccepting(null);
|
||||
}
|
||||
@@ -59,12 +59,12 @@ export default function RequestsScreen() {
|
||||
|
||||
function decline(req: ContactRequest) {
|
||||
Alert.alert(
|
||||
'Decline request',
|
||||
`Decline request from ${req.username ? '@' + req.username : shortAddr(req.from)}?`,
|
||||
'Отклонить запрос',
|
||||
`Отклонить запрос от ${req.username ? '@' + req.username : shortAddr(req.from)}?`,
|
||||
[
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{ text: 'Отмена', style: 'cancel' },
|
||||
{
|
||||
text: 'Decline',
|
||||
text: 'Отклонить',
|
||||
style: 'destructive',
|
||||
onPress: () => setRequests(requests.filter(r => r.txHash !== req.txHash)),
|
||||
},
|
||||
@@ -91,7 +91,7 @@ export default function RequestsScreen() {
|
||||
{name}
|
||||
</Text>
|
||||
<Text style={{ color: '#8b8b8b', fontSize: 12, marginTop: 2 }}>
|
||||
wants to message you · {relativeTime(req.timestamp)}
|
||||
хочет добавить вас в контакты · {relativeTime(req.timestamp)}
|
||||
</Text>
|
||||
{req.intro ? (
|
||||
<Text
|
||||
@@ -123,7 +123,7 @@ export default function RequestsScreen() {
|
||||
{isAccepting ? (
|
||||
<ActivityIndicator size="small" color="#ffffff" />
|
||||
) : (
|
||||
<Text style={{ color: '#ffffff', fontWeight: '700', fontSize: 13 }}>Accept</Text>
|
||||
<Text style={{ color: '#ffffff', fontWeight: '700', fontSize: 13 }}>Принять</Text>
|
||||
)}
|
||||
</Pressable>
|
||||
<Pressable
|
||||
@@ -137,7 +137,7 @@ export default function RequestsScreen() {
|
||||
borderWidth: 1, borderColor: '#1f1f1f',
|
||||
})}
|
||||
>
|
||||
<Text style={{ color: '#ffffff', fontWeight: '600', fontSize: 13 }}>Decline</Text>
|
||||
<Text style={{ color: '#ffffff', fontWeight: '600', fontSize: 13 }}>Отклонить</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
@@ -147,16 +147,16 @@ export default function RequestsScreen() {
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, backgroundColor: '#000000', paddingTop: insets.top }}>
|
||||
<TabHeader title="Notifications" />
|
||||
<TabHeader title="Уведомления" />
|
||||
|
||||
{requests.length === 0 ? (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 32 }}>
|
||||
<Ionicons name="notifications-outline" size={42} color="#3a3a3a" />
|
||||
<Text style={{ color: '#ffffff', fontSize: 16, fontWeight: '700', marginTop: 10 }}>
|
||||
All caught up
|
||||
Всё прочитано
|
||||
</Text>
|
||||
<Text style={{ color: '#8b8b8b', fontSize: 13, textAlign: 'center', marginTop: 6, lineHeight: 19 }}>
|
||||
Contact requests and network events will appear here.
|
||||
Запросы на общение и события сети появятся здесь.
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user