Skip to content

Commit cb15bfa

Browse files
committed
fix(mobile): add Public notes view to Quick Access
1 parent 597b465 commit cb15bfa

File tree

8 files changed

+49
-11
lines changed

8 files changed

+49
-11
lines changed

apps/mobile/v1/src/screens/FolderNotes/components/NotesList/NotesHeader.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ interface NotesHeaderProps {
1010
filteredNotesCount: number;
1111
totalNotesCount: number;
1212
hasActiveFilters: boolean;
13-
viewType?: 'all' | 'starred' | 'archived' | 'trash';
13+
viewType?: 'all' | 'starred' | 'public' | 'archived' | 'trash';
1414
subfoldersCount: number;
1515
onFilterPress: () => void;
1616
onCreateNotePress: () => void;
@@ -36,7 +36,7 @@ export const NotesHeader: React.FC<NotesHeaderProps> = ({
3636
<View style={[styles.sectionHeader, { marginTop: subfoldersCount > 0 ? 12 : 16 }]}>
3737
<Text style={[styles.sectionTitle, { color: theme.colors.mutedForeground }]}>
3838
NOTES ({String(filteredNotesCount || 0)})
39-
{filteredNotesCount !== totalNotesCount && ` (${totalNotesCount} total)`}
39+
{viewType !== 'public' && filteredNotesCount !== totalNotesCount && ` (${totalNotesCount} total)`}
4040
</Text>
4141
<GlassView glassEffectStyle="regular" style={[styles.squareButtonGlass, { backgroundColor: theme.isDark ? 'rgba(255, 255, 255, 0.01)' : 'rgba(0, 0, 0, 0.01)' }]}>
4242
<TouchableOpacity

apps/mobile/v1/src/screens/FolderNotes/components/NotesList/index.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const FAB_ANIMATION_DISTANCE = 20; // Distance to slide up during animation
3333

3434
interface RouteParams {
3535
folderId?: string;
36-
viewType?: 'all' | 'starred' | 'archived' | 'trash';
36+
viewType?: 'all' | 'starred' | 'public' | 'archived' | 'trash';
3737
searchQuery?: string;
3838
folderName?: string;
3939
}
@@ -409,8 +409,16 @@ export default function NotesList({ navigation, route, renderHeader, scrollY: pa
409409
}
410410
}, [notes]);
411411

412+
// Create effective filter config - auto-enable showPublicOnly for public view
413+
const effectiveFilterConfig = useMemo(() => {
414+
if (viewType === 'public') {
415+
return { ...filterConfig, showPublicOnly: true };
416+
}
417+
return filterConfig;
418+
}, [filterConfig, viewType]);
419+
412420
// Filter and sort notes (enhanced cache is populated above)
413-
const filteredNotes = useNotesFiltering(notes, searchQuery, filterConfig, sortConfig);
421+
const filteredNotes = useNotesFiltering(notes, searchQuery, effectiveFilterConfig, sortConfig);
414422

415423
// Pre-calculate folder paths
416424
const folderPathsMap = useFolderPaths(allFolders);

apps/mobile/v1/src/screens/FolderNotes/components/NotesList/useNotesLoader.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type { SortConfig } from './FilterSortSheet';
1010

1111
interface UseNotesLoaderProps {
1212
folderId?: string;
13-
viewType?: 'all' | 'starred' | 'archived' | 'trash';
13+
viewType?: 'all' | 'starred' | 'public' | 'archived' | 'trash';
1414
sortConfig: SortConfig;
1515
userId?: string;
1616
screenFocusTime: React.MutableRefObject<number>;
@@ -224,6 +224,11 @@ export function useNotesLoader({
224224
// Add view type filters
225225
if (viewType === 'starred') {
226226
queryParams.starred = true;
227+
} else if (viewType === 'public') {
228+
// Public view: fetch all non-deleted, non-archived notes
229+
// Client-side filtering by isPublished happens in useNotesFiltering
230+
queryParams.deleted = false;
231+
queryParams.archived = false;
227232
} else if (viewType === 'archived') {
228233
queryParams.archived = true;
229234
} else if (viewType === 'trash') {

apps/mobile/v1/src/screens/FolderNotes/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ function getViewTitle(viewType: string): string {
2121
switch (viewType) {
2222
case 'all': return 'All Notes';
2323
case 'starred': return 'Starred';
24+
case 'public': return 'Public';
2425
case 'archived': return 'Archived';
2526
case 'trash': return 'Trash';
2627
default: return 'Notes';
@@ -30,7 +31,7 @@ function getViewTitle(viewType: string): string {
3031
interface FolderNotesScreenProps {
3132
folderId?: string;
3233
folderName?: string;
33-
viewType?: 'all' | 'starred' | 'archived' | 'trash';
34+
viewType?: 'all' | 'starred' | 'public' | 'archived' | 'trash';
3435
}
3536

3637
export default function FolderNotesScreen({ folderId, folderName, viewType }: FolderNotesScreenProps) {

apps/mobile/v1/src/screens/Home/index.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { GlassView } from 'expo-glass-effect';
77
import { LinearGradient } from 'expo-linear-gradient';
88
import { useRouter } from 'expo-router';
99
import React, { useCallback,useEffect, useMemo, useRef, useState } from 'react';
10-
import { ActivityIndicator, Alert, Animated, Image, Keyboard, RefreshControl, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
10+
import { ActivityIndicator, Alert, Animated, Dimensions, Image, Keyboard, RefreshControl, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
1111
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
1212

1313
import { OfflineIndicator } from '../../components/OfflineIndicator';
@@ -16,6 +16,11 @@ import { useNetworkStatus } from '../../hooks/useNetworkStatus';
1616
import { type Folder, type FolderCounts,useApiService } from '../../services/api';
1717
import { useTheme } from '../../theme';
1818

19+
// Calculate folder grid item width
20+
// Container has paddingHorizontal: 16 (32px total) and gap: 12
21+
const SCREEN_WIDTH = Dimensions.get('window').width;
22+
const FOLDER_GRID_ITEM_WIDTH = (SCREEN_WIDTH - 32 - 12) / 2;
23+
1924
// Special views configuration matching web app
2025
const SPECIAL_VIEWS = [
2126
{
@@ -28,6 +33,11 @@ const SPECIAL_VIEWS = [
2833
label: 'Starred',
2934
icon: 'star' as const,
3035
},
36+
{
37+
id: 'public',
38+
label: 'Public',
39+
icon: 'globe' as const,
40+
},
3141
{
3242
id: 'archived',
3343
label: 'Archived',
@@ -62,6 +72,7 @@ export default function HomeScreen() {
6272
const [counts, setCounts] = useState({
6373
all: 0,
6474
starred: 0,
75+
public: 0,
6576
archived: 0,
6677
trash: 0,
6778
});
@@ -159,6 +170,7 @@ export default function HomeScreen() {
159170
const newCounts = {
160171
all: noteCounts.all || 0,
161172
starred: noteCounts.starred || 0,
173+
public: noteCounts.public || 0,
162174
archived: noteCounts.archived || 0,
163175
trash: noteCounts.trash || 0,
164176
};
@@ -170,7 +182,7 @@ export default function HomeScreen() {
170182
} catch (error) {
171183
if (__DEV__) console.error('Failed to load folders data:', error);
172184
setAllFolders([]);
173-
setCounts({ all: 0, starred: 0, archived: 0, trash: 0 });
185+
setCounts({ all: 0, starred: 0, public: 0, archived: 0, trash: 0 });
174186
} finally {
175187
if (!isRefresh) {
176188
setLoading(false);
@@ -262,7 +274,7 @@ export default function HomeScreen() {
262274
setRefreshing(true);
263275
// Clear current data to force fresh load
264276
setAllFolders([]);
265-
setCounts({ all: 0, starred: 0, archived: 0, trash: 0 });
277+
setCounts({ all: 0, starred: 0, public: 0, archived: 0, trash: 0 });
266278
await loadFoldersData(true, true); // isRefresh=true, forceRefresh=true
267279
} finally {
268280
setRefreshing(false);
@@ -930,7 +942,7 @@ const styles = StyleSheet.create({
930942
backgroundColor: 'rgba(0, 0, 0, 0.01)',
931943
},
932944
glassCreateFolderGrid: {
933-
width: '48%',
945+
width: FOLDER_GRID_ITEM_WIDTH,
934946
borderRadius: FOLDER_CARD.BORDER_RADIUS,
935947
overflow: 'hidden',
936948
backgroundColor: 'rgba(0, 0, 0, 0.01)',
@@ -954,7 +966,7 @@ const styles = StyleSheet.create({
954966
paddingRight: 12,
955967
},
956968
folderItemGrid: {
957-
width: '48%',
969+
width: FOLDER_GRID_ITEM_WIDTH,
958970
padding: 16,
959971
minHeight: 100,
960972
borderWidth: 1,

apps/mobile/v1/src/services/api/databaseCache.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ export async function getCachedNotes(filters?: {
156156
starred?: boolean;
157157
archived?: boolean;
158158
deleted?: boolean;
159+
isPublic?: boolean;
159160
}): Promise<Note[]> {
160161
try {
161162
const db = getDatabase();
@@ -179,6 +180,10 @@ export async function getCachedNotes(filters?: {
179180
conditions.push('deleted = ?');
180181
params.push(filters.deleted ? 1 : 0);
181182
}
183+
if (filters?.isPublic !== undefined) {
184+
conditions.push('is_published = ?');
185+
params.push(filters.isPublic ? 1 : 0);
186+
}
182187

183188
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
184189

apps/mobile/v1/src/services/api/notes/core.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ export function createNotesApi(getToken: AuthTokenGetter, getUserId: () => strin
9393
if (note.deleted !== params.deleted) return false;
9494
}
9595

96+
// Filter by isPublic (published notes)
97+
if (params.isPublic !== undefined) {
98+
if (note.isPublished !== params.isPublic) return false;
99+
}
100+
96101
return true;
97102
});
98103
};
@@ -322,6 +327,7 @@ export function createNotesApi(getToken: AuthTokenGetter, getUserId: () => strin
322327
starred: params?.starred as boolean | undefined,
323328
archived: params?.archived as boolean | undefined,
324329
deleted: params?.deleted as boolean | undefined,
330+
isPublic: params?.isPublic as boolean | undefined,
325331
};
326332

327333
// Step 1: Try to get from local database cache

apps/mobile/v1/src/services/api/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ export interface NoteQueryParams {
109109
archived?: boolean;
110110
deleted?: boolean;
111111
hidden?: boolean;
112+
isPublic?: boolean;
112113
}
113114

114115
export interface EmptyTrashResponse {

0 commit comments

Comments
 (0)