Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(agenda): allow to hide agenda events and their recurrences #597

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"false": "Non active",
"true": "Active"
},
"agenda": "Agenda",
"agent": "Agent",
"all": "All",
"appFeedback": "App Feedback",
Expand Down Expand Up @@ -157,7 +158,9 @@
"follow": "Follow",
"free": "Free",
"grade": "Grade",
"hiddenEvents": "Hidden events",
"hide": "Hide",
"hideInAgenda": "Hide in Agenda",
"hour": "Hour",
"hours": "Hour",
"icon": "Icon",
Expand Down Expand Up @@ -315,6 +318,10 @@
"courseGuideScreen": {
"title": "Course guide"
},
"courseHideEventScreen": {
"button": "Show in Agenda",
"selectItems": "Select all"
},
"courseIconPickerScreen": {
"title": "Pick an icon"
},
Expand Down Expand Up @@ -532,7 +539,10 @@
"title": "Offers screen"
},
"lectureScreen": {
"courseFilesCta": "Go to course files"
"courseFilesCta": "Go to course files",
"hideEventAlertTitle": "Hide event",
"hideEventAlertMessage": " You are hiding the {{ day }} {{ title }} event from {{ fromTime }} to {{ toTime }}",
"hideEventButtonTitle": "Hide from the agenda"
},
"libraryScreen": {
"title": "Library"
Expand Down
12 changes: 11 additions & 1 deletion assets/translations/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"false": "Non attiva",
"true": "Attiva"
},
"agenda": "Agenda",
"agent": "Operatore",
"all": "Tutti",
"appFeedback": "Segnalazioni App",
Expand Down Expand Up @@ -164,7 +165,9 @@
"follow": "Segui",
"free": "Libera",
"grade": "Voto",
"hiddenEvents": "Eventi nascosti",
"hide": "Nascondi",
"hideInAgenda": "Nascondi in agenda",
"hour": "Orario",
"hours": "Ore",
"icon": "Icona",
Expand Down Expand Up @@ -326,6 +329,10 @@
"courseGuideScreen": {
"title": "Guida del corso"
},
"courseHideEventScreen": {
"button": "Mostra in Agenda",
"selectItems": "Seleziona tutti"
},
"courseIconPickerScreen": {
"title": "Seleziona un'icona"
},
Expand Down Expand Up @@ -546,7 +553,10 @@
"title": "Offerte di lavoro"
},
"lectureScreen": {
"courseFilesCta": "Vai al materiale del corso"
"courseFilesCta": "Vai al materiale del corso",
"hideEventAlertTitle": "Nascondi Evento",
"hideEventAlertMessage": "Stai nascondendo l'evento di: {{ title }} di {{ day }} dalle {{ fromTime }} alle {{ toTime }}",
"hideEventButtonTitle": "Nascondi evendo dall'agenda"
},
"libraryScreen": {
"title": "Biblioteca"
Expand Down
55 changes: 27 additions & 28 deletions src/core/components/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { useRef } from 'react';
import {
Animated,
StyleProp,
StyleSheet,
TextStyle,
Expand All @@ -9,12 +7,14 @@ import {
ViewStyle,
} from 'react-native';

import { faCheck } from '@fortawesome/free-solid-svg-icons';
import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
import { faSquare, faSquareCheck } from '@fortawesome/free-regular-svg-icons';
import { Icon } from '@lib/ui/components/Icon';
import { Text } from '@lib/ui/components/Text';
import { useStylesheet } from '@lib/ui/hooks/useStylesheet';
import { Theme } from '@lib/ui/types/Theme';

// faSquare, faSquareCheck
export const Checkbox = ({
text,
onPress,
Expand All @@ -23,53 +23,55 @@ export const Checkbox = ({
textStyle,
checkboxStyle,
disable,
dimension = 'default',
icon,
}: {
text: string;
text?: string;
onPress: () => void;
isChecked: boolean;
containerStyle?: StyleProp<ViewStyle>;
textStyle?: StyleProp<TextStyle>;
checkboxStyle?: StyleProp<ViewStyle>;
disable?: boolean;
dimension?: 'default' | 'small';
icon?: IconDefinition;
}) => {
const styles = useStylesheet(createStyles);

const animatedWidth = useRef(new Animated.Value(0)).current;

const startAnimation = () => {
const toValue = isChecked ? 30 : 0;
Animated.timing(animatedWidth, {
toValue: toValue,
duration: 500,
useNativeDriver: false,
}).start();
};

return (
<View style={[styles.container, containerStyle]}>
<TouchableOpacity
style={[
styles.checkbox,
checkboxStyle,
isChecked && styles.checkboxSelected,
dimension === 'small' && { height: 20, width: 20 },
]}
disabled={disable ?? false}
onPress={() => {
startAnimation();
onPress();
}}
>
<Animated.View
<View
style={{
width: animatedWidth,
height: 30,
display: isChecked ? 'flex' : 'none',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Icon icon={faCheck} color="white" size={20} />
</Animated.View>
{isChecked ? (
<Icon
icon={icon ? icon : faSquareCheck}
style={styles.checkboxIcon}
size={dimension === 'small' ? 15 : 20}
/>
) : (
<Icon
icon={faSquare}
style={styles.checkboxIcon}
size={dimension === 'small' ? 15 : 20}
/>
)}
</View>
</TouchableOpacity>
<Text style={[styles.text, textStyle]}>{text}</Text>
</View>
Expand All @@ -85,16 +87,13 @@ const createStyles = ({ palettes, spacing, fontSizes, dark }: Theme) =>
marginHorizontal: spacing[5],
},
checkbox: {
borderColor: palettes.navy[dark ? '50' : '600'],
borderWidth: 1,
borderRadius: 5,
height: 25,
width: 25,
justifyContent: 'center',
alignItems: 'center',
},
checkboxSelected: {
backgroundColor: palettes.navy[dark ? '50' : '600'],
checkboxIcon: {
color: palettes.navy[dark ? '50' : '600'],
},
text: {
fontSize: fontSizes.sm,
Expand Down
3 changes: 3 additions & 0 deletions src/core/contexts/PreferencesContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { PlaceOverview } from '@polito/api-client';
import { PersonOverview } from '@polito/api-client/models';

import { AgendaTypesFilterState } from '../../features/agenda/types/AgendaTypesFilterState';
import { HiddenRecurrence } from '../../features/courses/types/Recurrence';

export const editablePreferenceKeys = [
'lastInstalledVersion',
Expand Down Expand Up @@ -80,6 +81,8 @@ export interface CoursePreferencesProps {
icon?: string;
isHidden: boolean;
order?: number;
isHiddenInAgenda: boolean;
itemsToHideInAgenda?: HiddenRecurrence[];
}

export const PreferencesContext = createContext<
Expand Down
1 change: 1 addition & 0 deletions src/core/queries/courseHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const setupCourses = (
coursePreferences[newC.uniqueShortcode] = {
color: colorData.color,
isHidden: false,
isHiddenInAgenda: false,
};
hasNewPreferences = true;
}
Expand Down
5 changes: 4 additions & 1 deletion src/features/agenda/components/DailyAgenda.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useStylesheet } from '@lib/ui/hooks/useStylesheet';
import { Theme } from '@lib/ui/types/Theme';

import { isCurrentMonth, isCurrentYear } from '../../../utils/dates';
import { useHideEventFilter } from '../hooks/useHideEventFilter';
import { AgendaDay } from '../types/AgendaDay';
import { BookingCard } from './BookingCard';
import { DeadlineCard } from './DeadlineCard';
Expand All @@ -29,6 +30,8 @@ export const DailyAgenda = ({ agendaDay, isEmptyWeek, onLayout }: Props) => {
!isCurrentMonth(agendaDay.date) && agendaDay.date.toFormat('MMM');
const year = !isCurrentYear(agendaDay.date) && agendaDay.date.toFormat('y');

const filteredAgendaDay = useHideEventFilter(agendaDay.items);

return (
<Row onLayout={onLayout}>
<Col style={styles.dayColumn} align="stretch">
Expand Down Expand Up @@ -68,7 +71,7 @@ export const DailyAgenda = ({ agendaDay, isEmptyWeek, onLayout }: Props) => {
<EmptyDay />
)
) : (
agendaDay?.items.map(item => {
filteredAgendaDay.map(item => {
switch (item.type) {
case 'booking':
return <BookingCard key={item.key} item={item} />;
Expand Down
36 changes: 36 additions & 0 deletions src/features/agenda/hooks/useHideEventFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { usePreferencesContext } from '../../../core/contexts/PreferencesContext';
import { resolvePlaceId } from '../../places/utils/resolvePlaceId';
import { AgendaItem } from '../types/AgendaItem';

export const useHideEventFilter = (data: AgendaItem[]) => {
const { courses } = usePreferencesContext();

return data.filter(item => {
if (item.type !== 'lecture') return true;

if (!item.uniqueShortcode) return true;

const course = courses[item.uniqueShortcode];

if (course.isHiddenInAgenda) return false;

if (!course.itemsToHideInAgenda) return true;

const lectureRecurrence = {
day: item.start.weekday,
start: item.fromTime,
end: item.toTime,
room: item.place ? resolvePlaceId(item.place) : '',
};

const isLectureHidden = course.itemsToHideInAgenda.some(
hiddenRecurrence =>
hiddenRecurrence.day === lectureRecurrence.day &&
hiddenRecurrence.start === lectureRecurrence.start &&
hiddenRecurrence.end === lectureRecurrence.end &&
hiddenRecurrence.room === lectureRecurrence.room,
);

return !isLectureHidden;
});
};
1 change: 1 addition & 0 deletions src/features/agenda/queries/agendaHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ const groupItemsByDay = (
teacherId: lecture.teacherId,
virtualClassrooms: lecture.virtualClassrooms,
description: lecture.description,
uniqueShortcode: lecture.uniqueShortcode,
};
return item;
}),
Expand Down
5 changes: 4 additions & 1 deletion src/features/agenda/screens/AgendaWeekScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { DeadlineCard } from '../components/DeadlineCard';
import { ExamCard } from '../components/ExamCard';
import { LectureCard } from '../components/LectureCard';
import { WeekFilter } from '../components/WeekFilter';
import { useHideEventFilter } from '../hooks/useHideEventFilter';
import {
getAgendaWeekQueryKey,
useGetAgendaWeek,
Expand Down Expand Up @@ -83,6 +84,8 @@ export const AgendaWeekScreen = ({ navigation, route }: Props) => {
return weekData?.data?.flatMap(week => week.items) ?? [];
}, [weekData?.data]);

const filteredCalendarData = useHideEventFilter(calendarData);

const getNextWeek = useCallback(() => {
setCurrentWeek(w => {
const nextWeek = w.plus({ days: 7 });
Expand Down Expand Up @@ -257,7 +260,7 @@ export const AgendaWeekScreen = ({ navigation, route }: Props) => {
))}
{calendarHeight && (
<Calendar<AgendaItem>
events={calendarData}
events={filteredCalendarData}
headerContentStyle={styles.dayHeader}
weekDayHeaderHighlightColor={colors.background}
date={currentWeek}
Expand Down
Loading
Loading