Skip to content

Commit 49b0e55

Browse files
authored
simplify mobile demo app screens (selfxyz#1183)
* update layout structure * fix timeout * feedback
1 parent 79fdd04 commit 49b0e55

File tree

16 files changed

+779
-530
lines changed

16 files changed

+779
-530
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
4+
5+
import React from 'react';
6+
import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
7+
8+
type Props = {
9+
logs: string[];
10+
show: boolean;
11+
onToggle: () => void;
12+
};
13+
14+
export default function LogsPanel({ logs, show, onToggle }: Props) {
15+
if (logs.length === 0) return null;
16+
return (
17+
<View style={styles.container}>
18+
<TouchableOpacity onPress={onToggle} style={styles.toggle}>
19+
<Text style={styles.toggleText}>{show ? `▼ Hide Logs (${logs.length})` : `▶ Show Logs (${logs.length})`}</Text>
20+
</TouchableOpacity>
21+
{show && (
22+
<ScrollView style={styles.logs} nestedScrollEnabled>
23+
{logs.map((log, idx) => (
24+
<Text key={idx} style={styles.entry}>
25+
{log}
26+
</Text>
27+
))}
28+
</ScrollView>
29+
)}
30+
</View>
31+
);
32+
}
33+
34+
const styles = StyleSheet.create({
35+
container: {
36+
marginTop: 8,
37+
},
38+
toggle: {
39+
padding: 8,
40+
backgroundColor: '#fff',
41+
borderRadius: 4,
42+
borderWidth: 1,
43+
borderColor: '#ffc107',
44+
},
45+
toggleText: {
46+
fontSize: 12,
47+
color: '#856404',
48+
textAlign: 'center',
49+
fontWeight: '600',
50+
},
51+
logs: {
52+
marginTop: 8,
53+
maxHeight: 200,
54+
backgroundColor: '#fff',
55+
borderRadius: 4,
56+
borderWidth: 1,
57+
borderColor: '#ffc107',
58+
padding: 8,
59+
},
60+
entry: {
61+
fontSize: 11,
62+
fontFamily: 'monospace',
63+
color: '#333',
64+
marginBottom: 4,
65+
},
66+
});
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
4+
5+
import React from 'react';
6+
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
7+
8+
type Props = {
9+
title: string;
10+
subtitle?: string;
11+
onPress: () => void;
12+
isWorking?: boolean;
13+
disabled?: boolean;
14+
};
15+
16+
export default function MenuButton({ title, subtitle, onPress, isWorking = false, disabled = false }: Props) {
17+
return (
18+
<TouchableOpacity
19+
style={[
20+
styles.menuButton,
21+
isWorking ? styles.workingButton : styles.placeholderButton,
22+
disabled && styles.disabledButton,
23+
]}
24+
onPress={onPress}
25+
activeOpacity={0.7}
26+
disabled={disabled}
27+
>
28+
<Text
29+
style={[
30+
styles.menuButtonText,
31+
isWorking ? styles.workingButtonText : styles.placeholderButtonText,
32+
disabled && styles.disabledButtonText,
33+
]}
34+
>
35+
{title}
36+
</Text>
37+
{subtitle ? (
38+
<Text
39+
style={[
40+
styles.menuButtonSubtitle,
41+
disabled
42+
? styles.disabledSubtitleText
43+
: isWorking
44+
? styles.workingButtonSubtitle
45+
: styles.placeholderButtonSubtitle,
46+
]}
47+
>
48+
{subtitle}
49+
</Text>
50+
) : null}
51+
</TouchableOpacity>
52+
);
53+
}
54+
55+
const styles = StyleSheet.create({
56+
menuButton: {
57+
width: '100%',
58+
paddingVertical: 16,
59+
paddingHorizontal: 24,
60+
borderRadius: 16,
61+
marginBottom: 16,
62+
shadowColor: '#1f2328',
63+
shadowOffset: {
64+
width: 0,
65+
height: 4,
66+
},
67+
shadowOpacity: 0.08,
68+
shadowRadius: 12,
69+
elevation: 4,
70+
},
71+
workingButton: {
72+
backgroundColor: '#ffffff',
73+
borderWidth: 1,
74+
borderColor: '#d1d9e0',
75+
},
76+
placeholderButton: {
77+
backgroundColor: '#ffffff',
78+
borderWidth: 1,
79+
borderColor: '#d1d9e0',
80+
},
81+
menuButtonText: {
82+
fontSize: 17,
83+
fontWeight: '600',
84+
textAlign: 'center',
85+
letterSpacing: -0.2,
86+
},
87+
menuButtonSubtitle: {
88+
fontSize: 12,
89+
marginTop: 6,
90+
textAlign: 'center',
91+
lineHeight: 18,
92+
opacity: 0.9,
93+
},
94+
workingButtonText: {
95+
color: '#0d1117',
96+
},
97+
placeholderButtonText: {
98+
color: '#0d1117',
99+
},
100+
placeholderButtonSubtitle: {
101+
color: '#656d76',
102+
},
103+
workingButtonSubtitle: {
104+
color: '#656d76',
105+
},
106+
disabledButton: {
107+
backgroundColor: '#f6f8fa',
108+
borderColor: '#d1d9e0',
109+
opacity: 0.7,
110+
},
111+
disabledButtonText: {
112+
color: '#8b949e',
113+
},
114+
disabledSubtitleText: {
115+
color: '#656d76',
116+
},
117+
});
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
4+
5+
import React from 'react';
6+
import { StyleSheet, Text, View } from 'react-native';
7+
8+
import ScreenLayout from './ScreenLayout';
9+
10+
type Props = {
11+
title: string;
12+
onBack: () => void;
13+
description: string;
14+
features: string[];
15+
};
16+
17+
export default function PlaceholderScreen({ title, onBack, description, features }: Props) {
18+
return (
19+
<ScreenLayout title={title} onBack={onBack}>
20+
<View style={styles.content}>
21+
<Text style={styles.description}>{description}</Text>
22+
23+
<View style={styles.features}>
24+
<Text style={styles.featureTitle}>Features (Not Implemented):</Text>
25+
{features.map((f, idx) => (
26+
<Text key={`${idx}-${f}`} style={styles.feature}>
27+
{f}
28+
</Text>
29+
))}
30+
</View>
31+
</View>
32+
</ScreenLayout>
33+
);
34+
}
35+
36+
const styles = StyleSheet.create({
37+
content: {
38+
flex: 1,
39+
justifyContent: 'center',
40+
},
41+
description: {
42+
fontSize: 16,
43+
textAlign: 'center',
44+
marginBottom: 24,
45+
lineHeight: 24,
46+
},
47+
features: {
48+
backgroundColor: '#f5f5f5',
49+
padding: 16,
50+
borderRadius: 8,
51+
marginBottom: 24,
52+
},
53+
featureTitle: {
54+
fontSize: 16,
55+
fontWeight: 'bold',
56+
marginBottom: 12,
57+
},
58+
feature: {
59+
fontSize: 14,
60+
marginBottom: 8,
61+
color: '#333',
62+
},
63+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
4+
5+
import React from 'react';
6+
import { StyleSheet, View, type ViewStyle } from 'react-native';
7+
8+
import SafeAreaScrollView from './SafeAreaScrollView';
9+
import StandardHeader from './StandardHeader';
10+
11+
type Props = {
12+
title: string;
13+
onBack: () => void;
14+
children: React.ReactNode;
15+
contentStyle?: ViewStyle;
16+
};
17+
18+
export default function ScreenLayout({ title, onBack, children, contentStyle }: Props) {
19+
return (
20+
<SafeAreaScrollView contentContainerStyle={styles.container} backgroundColor="#fafbfc">
21+
<StandardHeader title={title} onBack={onBack} />
22+
<View style={[styles.content, contentStyle]}>{children}</View>
23+
</SafeAreaScrollView>
24+
);
25+
}
26+
27+
const styles = StyleSheet.create({
28+
container: {
29+
flexGrow: 1,
30+
backgroundColor: '#fafbfc',
31+
paddingHorizontal: 24,
32+
paddingVertical: 20,
33+
},
34+
content: {
35+
flex: 1,
36+
},
37+
});
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
4+
5+
import { useCallback, useEffect, useState } from 'react';
6+
7+
import type { DocumentMetadata, IDDocument } from '@selfxyz/common/dist/esm/src/utils/types.js';
8+
import { getAllDocuments, useSelfClient } from '@selfxyz/mobile-sdk-alpha';
9+
10+
import { updateAfterDelete } from '../lib/catalog';
11+
12+
export type DocumentEntry = {
13+
metadata: DocumentMetadata;
14+
data: IDDocument;
15+
};
16+
17+
export function useDocuments() {
18+
const selfClient = useSelfClient();
19+
const [documents, setDocuments] = useState<DocumentEntry[]>([]);
20+
const [loading, setLoading] = useState(true);
21+
const [error, setError] = useState<string | null>(null);
22+
const [deleting, setDeleting] = useState<string | null>(null);
23+
24+
const refresh = useCallback(async () => {
25+
setLoading(true);
26+
setError(null);
27+
try {
28+
const all = await getAllDocuments(selfClient);
29+
setDocuments(Object.values(all));
30+
} catch (err) {
31+
setDocuments([]);
32+
setError(err instanceof Error ? err.message : String(err));
33+
} finally {
34+
setLoading(false);
35+
}
36+
}, [selfClient]);
37+
38+
useEffect(() => {
39+
refresh();
40+
}, [refresh]);
41+
42+
const deleteDocument = useCallback(
43+
async (documentId: string) => {
44+
setDeleting(documentId);
45+
try {
46+
await selfClient.deleteDocument(documentId);
47+
const currentCatalog = await selfClient.loadDocumentCatalog();
48+
const updatedCatalog = updateAfterDelete(currentCatalog, documentId);
49+
await selfClient.saveDocumentCatalog(updatedCatalog);
50+
await refresh();
51+
} finally {
52+
setDeleting(null);
53+
}
54+
},
55+
[selfClient, refresh],
56+
);
57+
58+
return { documents, loading, error, deleting, refresh, deleteDocument } as const;
59+
}

0 commit comments

Comments
 (0)