diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 8ee462b..05c6410 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -4,15 +4,18 @@
+
+
+
+
+
-
-
+
-
= ({
navigation,
toggleSidebar,
}: any) => {
- const {registers, activeRegister, updatedAt} = useStore();
+ const {registers, activeRegister, viewingRegisters, updatedAt} = useStore();
const [currentEvents, setCurrentEvents] = useState([]);
const [upcomingEvents, setUpcomingEvents] = useState([]);
@@ -63,60 +65,68 @@ const HomeScreen: React.FC = ({
return now.getHours() * 60 + now.getMinutes();
};
- // Process events from current register
+ // Process events from all viewing registers
useEffect(() => {
- if (!registers[activeRegister]?.cards) {
- setCurrentEvents([]);
- setUpcomingEvents([]);
- return;
- }
+ const processEvents = () => {
+ const currentDay = getCurrentDayKey();
+ const currentTimeMinutes = getCurrentTimeInMinutes();
+ const allEvents: EventInfo[] = [];
- const currentDay = getCurrentDayKey();
- const currentTimeMinutes = getCurrentTimeInMinutes();
- const allEvents: EventInfo[] = [];
+ // Ensure viewingRegisters is an array before processing
+ if (!Array.isArray(viewingRegisters)) {
+ return;
+ }
- // Extract all events for today from current register
- registers[activeRegister].cards.forEach((card: CardInterface) => {
- const todaySlots = card.days[currentDay] || [];
+ viewingRegisters.forEach(registerId => {
+ const register = registers[registerId];
+ // Ensure the register and its cards exist and are in the correct format
+ if (register && Array.isArray(register.cards)) {
+ register.cards.forEach((card: CardInterface) => {
+ const todaySlots = card.days[currentDay] || [];
- todaySlots.forEach((slot: Slots, index: number) => {
- const startMinutes = timeToMinutes(slot.start);
- const endMinutes = timeToMinutes(slot.end);
+ todaySlots.forEach((slot: Slots, index: number) => {
+ const startMinutes = timeToMinutes(slot.start);
+ const endMinutes = timeToMinutes(slot.end);
- allEvents.push({
- id: `${card.id}-${currentDay}-${index}`,
- title: card.title,
- startTime: slot.start,
- endTime: slot.end,
- roomName: slot.roomName || undefined,
- color: card.tagColor,
- cardId: card.id,
- registerId: activeRegister,
- isRunning:
- currentTimeMinutes >= startMinutes &&
- currentTimeMinutes <= endMinutes,
- });
+ allEvents.push({
+ id: `${card.id}-${currentDay}-${index}-${registerId}`,
+ title: card.title,
+ startTime: slot.start,
+ endTime: slot.end,
+ roomName: slot.roomName || undefined,
+ color: card.tagColor,
+ cardId: card.id,
+ registerId: registerId,
+ isRunning:
+ currentTimeMinutes >= startMinutes &&
+ currentTimeMinutes <= endMinutes,
+ });
+ });
+ });
+ }
});
- });
- // Sort events by start time
- allEvents.sort(
- (a, b) => timeToMinutes(a.startTime) - timeToMinutes(b.startTime),
- );
+ // Sort events by start time
+ allEvents.sort(
+ (a, b) => timeToMinutes(a.startTime) - timeToMinutes(b.startTime),
+ );
+
+ // Separate current and upcoming events
+ const running = allEvents.filter(event => event.isRunning);
+ const upcoming = allEvents
+ .filter(
+ event =>
+ !event.isRunning &&
+ timeToMinutes(event.startTime) > currentTimeMinutes,
+ )
+ .slice(0, 2); // Next 2 upcoming events
- // Separate current and upcoming events
- const running = allEvents.filter(event => event.isRunning);
- const upcoming = allEvents
- .filter(
- event =>
- !event.isRunning &&
- timeToMinutes(event.startTime) > currentTimeMinutes,
- )
- .slice(0, 2); // Next 2 upcoming events
+ setCurrentEvents(running);
+ setUpcomingEvents(upcoming);
+ };
- setCurrentEvents(running);
- setUpcomingEvents(upcoming);
- }, [registers, activeRegister, updatedAt]);
+ processEvents();
+ }, [registers, viewingRegisters, updatedAt]);
// Navigate to card details
const handleEventPress = (event: EventInfo) => {
@@ -195,9 +205,8 @@ const HomeScreen: React.FC = ({
No events scheduled for today
- Add subjects to{' '}
- {registers[activeRegister]?.name || 'your register'} to see your
- schedule
+ Please check that your selected registers have subjects scheduled
+ for today.
)}
@@ -324,4 +333,4 @@ const styles = StyleSheet.create({
},
});
-export default HomeScreen;
+export default HomeScreen;
\ No newline at end of file
diff --git a/src/screens/time-table/TimeTableScreen.tsx b/src/screens/time-table/TimeTableScreen.tsx
index 7f2a260..7d2a096 100644
--- a/src/screens/time-table/TimeTableScreen.tsx
+++ b/src/screens/time-table/TimeTableScreen.tsx
@@ -1,3 +1,5 @@
+// src/screens/time-table/TimeTableScreen.tsx
+
import React, {useState, useEffect} from 'react';
import {
View,
@@ -44,23 +46,15 @@ const TimeTableScreen: React.FC = ({
navigation,
handleMenuOpen: _handleMenuOpen,
}) => {
- const {registers, activeRegister, markPresent, selectedRegisters, setSelectedRegisters} = useStore();
+ const {registers, viewingRegisters, markPresent, setSelectedRegisters} = useStore();
const [subjects, setSubjects] = useState([]);
- const [isDropdownOpen, setIsDropdownOpen] = useState(false);
-
- // Initialize selectedRegisters if empty (handles first app launch)
- useEffect(() => {
- if (Object.keys(registers).length > 0 && selectedRegisters.length === 0) {
- setSelectedRegisters([activeRegister]);
- }
- }, [registers, activeRegister, selectedRegisters, setSelectedRegisters]);
// Convert store data to TimeTable format
useEffect(() => {
const convertedSubjects: Subject[] = [];
// Only process selected registers
- selectedRegisters.forEach(registerIdx => {
+ viewingRegisters.forEach(registerIdx => {
const register = registers[registerIdx];
if (register?.cards) {
@@ -109,47 +103,7 @@ const TimeTableScreen: React.FC = ({
});
setSubjects(convertedSubjects);
- }, [registers, selectedRegisters]);
-
- // Helper functions for register selection
- const getAllRegisterIds = () =>
- Object.keys(registers).map(key => parseInt(key, 10));
-
- const isAllSelected = () => {
- const allIds = getAllRegisterIds();
- return (
- allIds.length > 0 && allIds.every(id => selectedRegisters.includes(id))
- );
- };
-
- const toggleAllRegisters = () => {
- if (isAllSelected()) {
- setSelectedRegisters([]);
- } else {
- setSelectedRegisters(getAllRegisterIds());
- }
- };
-
- const toggleRegister = (registerId: number) => {
- if (selectedRegisters.includes(registerId)) {
- setSelectedRegisters(selectedRegisters.filter(id => id !== registerId));
- } else {
- setSelectedRegisters([...selectedRegisters, registerId]);
- }
- };
-
- const getDropdownDisplayText = () => {
- if (selectedRegisters.length === 0) {
- return 'No registers selected';
- }
- if (isAllSelected()) {
- return 'All Registers';
- }
- if (selectedRegisters.length === 1) {
- return registers[selectedRegisters[0]]?.name || 'Unknown Register';
- }
- return `${selectedRegisters.length} registers selected`;
- };
+ }, [registers, viewingRegisters]);
// Get current date for header display
const getCurrentDate = () => {
@@ -163,13 +117,6 @@ const TimeTableScreen: React.FC = ({
return (
- {isDropdownOpen && (
- setIsDropdownOpen(false)}
- />
- )}
@@ -189,82 +136,11 @@ const TimeTableScreen: React.FC = ({
style={styles.editIcon}
/>
-
- setIsDropdownOpen(!isDropdownOpen)}>
-
- {getDropdownDisplayText()}
-
-
- {isDropdownOpen ? '▲' : '▼'}
-
-
- {isDropdownOpen && (
-
-
-
-
- All Registers
-
-
-
- {getAllRegisterIds().map(registerId => (
- toggleRegister(registerId)}>
-
-
-
-
- {registers[registerId]?.name || 'Unknown Register'}
-
-
-
-
- ))}
-
- )}
-
{
acc[registerId] = registers[registerId]?.name || 'Unknown Register';
return acc;
@@ -281,20 +157,9 @@ const styles = StyleSheet.create({
flex: 1,
backgroundColor: '#18181B',
},
- overlay: {
- position: 'absolute',
- top: 0,
- left: 0,
- right: 0,
- bottom: 0,
- zIndex: 999,
- },
headerContainer: {
paddingHorizontal: 16,
paddingVertical: 10,
- // backgroundColor: '#1F1F23',
- // borderBottomWidth: 1,
- // borderBottomColor: '#2D2D2D',
marginBottom: 12,
flexDirection: 'row',
alignItems: 'center',
@@ -328,6 +193,7 @@ const styles = StyleSheet.create({
justifyContent: 'center',
alignItems: 'center',
alignSelf: 'center',
+ marginLeft: 'auto',
marginRight: 16,
},
editIcon: {
@@ -341,88 +207,5 @@ const styles = StyleSheet.create({
fontWeight: '500',
marginLeft: 36, // Align with Schedule text (icon width 28px + marginRight 8px)
},
- dropdownContainer: {
- position: 'relative',
- zIndex: 1000,
- minWidth: 150,
- maxWidth: 200,
- },
- dropdownButton: {
- backgroundColor: '#2D2D2D',
- borderRadius: 8,
- paddingHorizontal: 12,
- paddingVertical: 10,
- flexDirection: 'row',
- justifyContent: 'space-between',
- alignItems: 'center',
- borderWidth: 1,
- borderColor: '#404040',
- },
- dropdownButtonText: {
- color: '#FFFFFF',
- fontSize: 14,
- fontWeight: '500',
- flex: 1,
- marginRight: 8,
- },
- dropdownArrow: {
- color: '#8B5CF6',
- fontSize: 12,
- fontWeight: 'bold',
- },
- dropdownMenu: {
- position: 'absolute',
- top: '100%',
- left: 0,
- right: 0,
- backgroundColor: '#2D2D2D',
- borderRadius: 8,
- borderWidth: 1,
- borderColor: '#404040',
- marginTop: 4,
- maxHeight: 200,
- zIndex: 1001,
- overflow: 'hidden',
- },
- dropdownItem: {
- paddingHorizontal: 12,
- paddingVertical: 12,
- borderBottomWidth: 1,
- borderBottomColor: '#404040',
- },
- dropdownItemSelected: {
- backgroundColor: '#8B5CF620',
- },
- dropdownItemContent: {
- flexDirection: 'row',
- alignItems: 'center',
- flex: 1,
- overflow: 'hidden',
- },
- registerItem: {
- flexDirection: 'row',
- alignItems: 'center',
- flex: 1,
- overflow: 'hidden',
- },
- colorIndicator: {
- width: 16,
- height: 16,
- borderRadius: 8,
- marginRight: 10,
- borderWidth: 1,
- borderColor: '#3F3F46',
- },
- dropdownItemText: {
- color: '#FFFFFF',
- fontSize: 14,
- flex: 1,
- },
- dropdownItemTextSelected: {
- color: '#8B5CF6',
- fontWeight: '600',
- flex: 1,
- },
});
-
-export default TimeTableScreen;
+export default TimeTableScreen;
\ No newline at end of file
diff --git a/src/screens/user-settings/SettingsScreen.tsx b/src/screens/user-settings/SettingsScreen.tsx
index 28fec26..24e6c4a 100644
--- a/src/screens/user-settings/SettingsScreen.tsx
+++ b/src/screens/user-settings/SettingsScreen.tsx
@@ -1,3 +1,5 @@
+// src/screens/user-settings/SettingsScreen.tsx
+
import React, { useState, useEffect } from 'react';
import {
View,
@@ -37,6 +39,8 @@ const SettingsScreen: React.FC = () => {
registers,
activeRegister,
selectedRegisters,
+ viewingRegisters,
+ setViewingRegisters,
setDefaultTargetPercentage,
updateAllRegistersTargetPercentage,
selectedSchedules,
@@ -55,6 +59,10 @@ const SettingsScreen: React.FC = () => {
const [localLeadTime, setLocalLeadTime] = useState(notificationLeadTime);
const [localSchedules, setLocalSchedules] = useState(selectedSchedules);
+ const registerOptions = Object.keys(registers).map(key => ({
+ id: key,
+ name: registers[parseInt(key)].name,
+ }));
// Effects
useEffect(() => {
setAppVersion(packageJson.version);
@@ -108,22 +116,22 @@ const SettingsScreen: React.FC = () => {
console.log('Starting save to device...');
console.log('Available registers:', Object.keys(registers));
console.log('Selected registers from store:', selectedRegisters);
-
+
// Use all registers if no specific selection is available
- const currentSelectedRegisters = selectedRegisters && selectedRegisters.length > 0
- ? selectedRegisters
+ const currentSelectedRegisters = selectedRegisters && selectedRegisters.length > 0
+ ? selectedRegisters
: Object.keys(registers).map(key => parseInt(key, 10));
-
+
console.log('Using registers for export:', currentSelectedRegisters);
-
+
if (currentSelectedRegisters.length === 0) {
Alert.alert('No Data', 'No registers found to export. Please create some schedules first.');
return;
}
-
- await saveScheduleToDevice({
- selectedRegisters: currentSelectedRegisters,
- registers
+
+ await saveScheduleToDevice({
+ selectedRegisters: currentSelectedRegisters,
+ registers
});
} catch (error) {
console.error('Save to device error:', error);
@@ -137,22 +145,22 @@ const SettingsScreen: React.FC = () => {
console.log('Starting share schedule...');
console.log('Available registers:', Object.keys(registers));
console.log('Selected registers from store:', selectedRegisters);
-
+
// Use all registers if no specific selection is available
- const currentSelectedRegisters = selectedRegisters && selectedRegisters.length > 0
- ? selectedRegisters
+ const currentSelectedRegisters = selectedRegisters && selectedRegisters.length > 0
+ ? selectedRegisters
: Object.keys(registers).map(key => parseInt(key, 10));
-
+
console.log('Using registers for share:', currentSelectedRegisters);
-
+
if (currentSelectedRegisters.length === 0) {
Alert.alert('No Data', 'No registers found to share. Please create some schedules first.');
return;
}
-
- await shareSchedule({
- selectedRegisters: currentSelectedRegisters,
- registers
+
+ await shareSchedule({
+ selectedRegisters: currentSelectedRegisters,
+ registers
});
} catch (error) {
console.error('Share schedule error:', error);
@@ -164,7 +172,7 @@ const SettingsScreen: React.FC = () => {
const handleImportSchedule = async () => {
try {
console.log('Starting CSV import...');
-
+
if (!registers[activeRegister]) {
Alert.alert('Error', 'No active register found. Please create a register first.');
return;
@@ -173,7 +181,7 @@ const SettingsScreen: React.FC = () => {
// Use raw CSV content instead of parsed data
const csvContent = await pickCSVFileRaw();
console.log('Raw CSV Content received:', csvContent);
-
+
if (!csvContent) {
console.log('No CSV content received (user cancelled or error)');
return;
@@ -238,7 +246,6 @@ const SettingsScreen: React.FC = () => {
{registerInfo.name}
{registerInfo.totalCards} subjects
-
{/* Preferences Section */}
Preferences
@@ -294,6 +301,30 @@ const SettingsScreen: React.FC = () => {
+ {/* Schedule View Section */}
+
+ Schedule View
+ Select Registers to View
+ setViewingRegisters(items.map(Number))}
+ selectedItems={viewingRegisters.map(String)}
+ selectText="Pick Registers"
+ searchInputPlaceholderText="Search Registers..."
+ tagRemoveIconColor="#EF4444"
+ tagTextColor="#9a4848ff"
+ selectedItemTextColor="#4CAF50"
+ selectedItemIconColor="#4CAF50"
+ itemTextColor="#bb5656ff"
+ displayKey="name"
+ searchInputStyle={{ color: '#e23939ff' }}
+ submitButtonColor="#4CAF50"
+ submitButtonText="Apply"
+ styleMainWrapper={{ backgroundColor: '#27272A', borderRadius: 12, padding: 10 }}
+ />
+
+
{/* Notifications & Alerts Section */}
Notifications & Alerts
@@ -333,16 +364,15 @@ const SettingsScreen: React.FC = () => {
/>
-
{/* Utilities Section */}
Utilities
-
Save Schedule to Device
@@ -353,9 +383,9 @@ const SettingsScreen: React.FC = () => {
-
Share Schedule
@@ -366,9 +396,9 @@ const SettingsScreen: React.FC = () => {
-
Import Schedule from CSV
@@ -456,7 +486,6 @@ const SettingsScreen: React.FC = () => {
>
);
};
-
// Styles
const styles = StyleSheet.create({
container: {
@@ -713,5 +742,4 @@ const styles = StyleSheet.create({
color: '#A1A1AA',
},
});
-
export default SettingsScreen;
\ No newline at end of file
diff --git a/src/store/store.ts b/src/store/store.ts
index b0cd34e..427e3ad 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -1,3 +1,5 @@
+// src/store/store.ts
+
import {create} from 'zustand';
import {persist, createJSONStorage} from 'zustand/middleware';
import AsyncStorage from '@react-native-async-storage/async-storage';
@@ -22,6 +24,7 @@ interface StoreState {
updatedAt: Date | null;
defaultTargetPercentage: number;
selectedRegisters: number[];
+ viewingRegisters: number[]; // New state for global view
setRegisters: (regNo: number, cardsData: CardInterface[]) => void;
updateDate: (date: Date) => void;
setDefaultTargetPercentage: (percentage: number) => void;
@@ -30,14 +33,15 @@ interface StoreState {
changeCopyRegister: (registerId: number) => void;
setActiveRegister: (registerId: number) => void;
setSelectedRegisters: (selectedIds: number[]) => void;
-
+ setViewingRegisters: (selectedIds: number[]) => void; // New action
+
selectedSchedules: string[];
setSelectedSchedules: (schedules: string[]) => void;
// Notification Lead Time (in minutes)
notificationLeadTime: number;
setNotificationLeadTime: (time: number) => void;
-
+
addRegister: (registerId: number, registerName: string) => void;
renameRegister: (registerId: number, registerName: string) => void;
removeRegister: (registerId: number) => void;
@@ -141,26 +145,35 @@ export const useStore = create()(
copyRegister: 0,
updatedAt: null,
defaultTargetPercentage: 75,
- selectedRegisters: [0], // Initialize with default register
+ selectedRegisters: [0],
+ viewingRegisters: [0], // Initialize with the default active register
+
+ setViewingRegisters: (selectedIds: number[]) =>
+ set(() => ({
+ viewingRegisters: selectedIds,
+ })),
changeCopyRegister: (registerId: number) =>
set(() => ({
copyRegister: registerId,
})),
selectedSchedules: ['all'],
- setSelectedSchedules: (schedules: string[]) =>
- set({ selectedSchedules: schedules }),
+ setSelectedSchedules: (schedules: string[]) =>
+ set({ selectedSchedules: schedules }),
- // Lead time for notification (e.g., 10 minutes before)
- notificationLeadTime: 10,
- setNotificationLeadTime: (time: number) =>
- set({ notificationLeadTime: time }),
+ // Lead time for notification (e.g., 10 minutes before)
+ notificationLeadTime: 10,
+ setNotificationLeadTime: (time: number) =>
+ set({ notificationLeadTime: time }),
setActiveRegister: (registerId: number) =>
set(state => ({
activeRegister: registerId,
// If no registers are selected, select the new active register
- selectedRegisters: state.selectedRegisters.length === 0 ? [registerId] : state.selectedRegisters,
+ selectedRegisters:
+ state.selectedRegisters.length === 0
+ ? [registerId]
+ : state.selectedRegisters,
})),
setSelectedRegisters: (selectedIds: number[]) =>
@@ -198,10 +211,11 @@ export const useStore = create()(
...state.registers,
[registerId]: {
...state.registers[registerId],
- cards: state.registers[registerId]?.cards.map(card => ({
- ...card,
- target_percentage: percentage,
- })) || [],
+ cards:
+ state.registers[registerId]?.cards.map(card => ({
+ ...card,
+ target_percentage: percentage,
+ })) || [],
},
},
})),
@@ -267,7 +281,7 @@ export const useStore = create()(
removeRegister: (registerId: number) =>
set(state => {
- const registers = {...state.registers};
+ const registers = { ...state.registers };
if (registerId in registers) {
const keys = Object.keys(registers)
.map(Number)
@@ -282,15 +296,32 @@ export const useStore = create()(
state.activeRegister === registerId ? 0 : state.activeRegister;
// Remove the deleted register from selectedRegisters and ensure valid selection
- let newSelectedRegisters = state.selectedRegisters.filter(id => id !== registerId);
- if (newSelectedRegisters.length === 0 && Object.keys(registers).length > 0) {
+ let newSelectedRegisters = state.selectedRegisters.filter(
+ id => id !== registerId,
+ );
+ if (
+ newSelectedRegisters.length === 0 &&
+ Object.keys(registers).length > 0
+ ) {
newSelectedRegisters = [newActiveRegister];
}
+ // Remove the deleted register from viewingRegisters
+ let newViewingRegisters = state.viewingRegisters.filter(
+ id => id !== registerId,
+ );
+ if (
+ newViewingRegisters.length === 0 &&
+ Object.keys(registers).length > 0
+ ) {
+ newViewingRegisters = [newActiveRegister];
+ }
+
return {
registers,
activeRegister: newActiveRegister,
selectedRegisters: newSelectedRegisters,
+ viewingRegisters: newViewingRegisters,
};
}
return state;
@@ -361,7 +392,12 @@ export const useStore = create()(
},
},
})),
- markAbsentWithDate: (date: Date, cardId: number, registerId: number, timeSlot?: string) =>
+ markAbsentWithDate: (
+ date: Date,
+ cardId: number,
+ registerId: number,
+ timeSlot?: string,
+ ) =>
set(state => {
const register = state.registers[registerId];
const card = register.cards.find(
@@ -402,7 +438,12 @@ export const useStore = create()(
updatedAt: new Date(),
};
}),
- markPresentWithDate: (date: Date, cardId: number, registerId: number, timeSlot?: string) =>
+ markPresentWithDate: (
+ date: Date,
+ cardId: number,
+ registerId: number,
+ timeSlot?: string,
+ ) =>
set(state => {
const register = state.registers[registerId];
const card = register.cards.find(
@@ -679,4 +720,4 @@ export const useStore = create()(
),
);
-export default useStore;
+export default useStore;
\ No newline at end of file