date-fns#isToday TypeScript Examples
The following examples show how to use
date-fns#isToday.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: formatDate.ts From TidGi-Desktop with Mozilla Public License 2.0 | 6 votes |
formatDate = (date: Date): string => {
if (isToday(date)) {
return format(date, 'p');
}
if (isTomorrow(date)) {
return `tomorrow at ${format(date, 'p')}`;
}
return format(date, 'PPPp');
}
Example #2
Source File: chartDataHelper.ts From korona-info with MIT License | 5 votes |
getInfectionsToday = (confirmed: Confirmed[]) => {
const infectionsToday = confirmed.filter(infection =>
isToday(new Date(infection.date))
);
return infectionsToday.length || 0;
}
Example #3
Source File: date.ts From ngx-gantt with MIT License | 5 votes |
isToday() {
return isToday(this.value);
}
Example #4
Source File: index.tsx From gobarber-web with MIT License | 4 votes |
Dashboard: React.FC = () => {
const { signOut, user } = useAuth();
const [selectedDate, setSelectedDate] = useState(new Date());
const [currentMonth, setCurrentMonth] = useState(new Date());
const [monthAvailability, setMonthAvailability] = useState<
MonthAvailabilityItem[]
>([]);
const [appointments, setAppointments] = useState<Appointment[]>([]);
const handleDateChange = useCallback((day: Date, modifiers: DayModifiers) => {
if (modifiers.available && !modifiers.disabled) {
setSelectedDate(day);
}
}, []);
const handleMonthChange = useCallback((month: Date) => {
setCurrentMonth(month);
}, []);
useEffect(() => {
api
.get(`/providers/${user.id}/month-availability`, {
params: {
year: currentMonth.getFullYear(),
month: currentMonth.getMonth() + 1,
},
})
.then(response => setMonthAvailability(response.data));
}, [currentMonth, user.id]);
useEffect(() => {
api
.get<Appointment[]>('/appointments/me', {
params: {
year: selectedDate.getFullYear(),
month: selectedDate.getMonth() + 1,
day: selectedDate.getDate(),
},
})
.then(response => {
const appointmentsFormatted = response.data.map(appointment => ({
...appointment,
hourFormatted: format(parseISO(appointment.date), 'HH:mm'),
}));
setAppointments(appointmentsFormatted);
});
}, [selectedDate]);
const disableDays = useMemo(() => {
return monthAvailability
.filter(monthDay => monthDay.available === false)
.map(monthDay => {
const year = currentMonth.getFullYear();
const month = currentMonth.getMonth();
return new Date(year, month, monthDay.day);
});
}, [currentMonth, monthAvailability]);
const selectedDateAsText = useMemo(() => {
return format(selectedDate, "'Dia' dd 'de' MMMM", { locale: ptBR });
}, [selectedDate]);
const selectedWeekDay = useMemo(() => {
return format(selectedDate, 'cccc', { locale: ptBR });
}, [selectedDate]);
const morningAppointments = useMemo(() => {
return appointments.filter(appointment => {
return parseISO(appointment.date).getHours() < 12;
});
}, [appointments]);
const afternoonAppointments = useMemo(() => {
return appointments.filter(appointment => {
return parseISO(appointment.date).getHours() >= 12;
});
}, [appointments]);
const nextAppointment = useMemo(() => {
return appointments.find(appointment =>
isAfter(parseISO(appointment.date), new Date()),
);
}, [appointments]);
return (
<S.Container>
<S.Header>
<S.HeaderContent>
<img src={logoImg} alt="Logo GoBarber" />
<S.HeaderProfile>
<img
src={
user.avatar_url ||
'https://api.adorable.io/avatars/56/[email protected]'
}
alt={user.name}
/>
<div>
<span>Bem-vindo,</span>
<Link to="/profile">
<strong>{user.name}</strong>
</Link>
</div>
</S.HeaderProfile>
<button type="button" onClick={signOut}>
<FiPower size={20} />
</button>
</S.HeaderContent>
</S.Header>
<S.Content>
<S.Schedule>
<h1>Horários agendados</h1>
<p>
{isToday(selectedDate) && <span>Hoje</span>}
<span>{selectedDateAsText}</span>
<span>{`${selectedWeekDay}-feira`}</span>
</p>
{isToday(selectedDate) && nextAppointment && (
<S.NextAppointment>
<strong>Atendimento a seguir</strong>
<div>
<img
src={
nextAppointment.user.avatar_url ||
'https://api.adorable.io/avatars/80/[email protected]'
}
alt={nextAppointment.user.name}
/>
<strong>{nextAppointment.user.name}</strong>
<span>
<FiClock size={24} />
{nextAppointment.hourFormatted}
</span>
</div>
</S.NextAppointment>
)}
<S.Section>
<strong>Manhã</strong>
{morningAppointments.length === 0 && (
<p>Nenhum agendamento neste período</p>
)}
{morningAppointments.map(appointment => (
<S.Appointment key={appointment.id}>
<span>
<FiClock size={20} />
{appointment.hourFormatted}
</span>
<div>
<img
src={
appointment.user.avatar_url ||
'https://api.adorable.io/avatars/56/[email protected]'
}
alt={appointment.user.name}
/>
<strong>{appointment.user.name}</strong>
</div>
</S.Appointment>
))}
</S.Section>
<S.Section>
<strong>Tarde</strong>
{afternoonAppointments.length === 0 && (
<p>Nenhum agendamento neste período</p>
)}
{afternoonAppointments.map(appointment => (
<S.Appointment key={appointment.id}>
<span>
<FiClock size={20} />
{appointment.hourFormatted}
</span>
<div>
<img
src={
appointment.user.avatar_url ||
'https://api.adorable.io/avatars/56/[email protected]'
}
alt={appointment.user.name}
/>
<strong>{appointment.user.name}</strong>
</div>
</S.Appointment>
))}
</S.Section>
</S.Schedule>
<S.Calendar>
<DayPicker
weekdaysShort={['D', 'S', 'T', 'Q', 'Q', 'S', 'S']}
fromMonth={new Date()}
disabledDays={[{ daysOfWeek: [0, 6] }, ...disableDays]}
modifiers={{
available: { daysOfWeek: [1, 2, 3, 4, 5] },
}}
onMonthChange={handleMonthChange}
selectedDays={selectedDate}
onDayClick={handleDateChange}
months={[
'Janeiro',
'Fevereiro',
'Março',
'Abril',
'Maio',
'Junho',
'Julho',
'Agosto',
'Setembro',
'Outubro',
'Novembro',
'Dezembro',
]}
/>
</S.Calendar>
</S.Content>
</S.Container>
);
}
Example #5
Source File: tracing.tsx From protect-scotland with Apache License 2.0 | 4 votes |
Tracing: FC = () => {
const [showSpinner, setShowSpinner] = useState(false);
const {checked, paused, deleteReminder} = useReminder();
const {t} = useTranslation();
const navigation = useNavigation();
const {enabled, status, contacts, start} = useExposure();
const tracingActive = enabled && status.state === StatusState.active;
const pauseDate = new Date(Number(paused));
const {isolationDuration} = useSettings();
const hasContact = hasCurrentExposure(isolationDuration, contacts);
if (!checked) {
return null;
}
const renderActive = () => (
<>
<Text variant="h3" style={styles.active}>
{t('tracing:status:heading')}
</Text>
<Spacing s={20} />
<View style={styles.row}>
<Image
style={styles.moduleImage as ImageStyle}
source={IconTracingActive}
accessibilityIgnoresInvertColors={false}
/>
<Text variant="h1" style={styles.active}>
{t('tracing:status:active')}
</Text>
</View>
<Spacing s={20} />
<Markdown>{t('tracing:message')}</Markdown>
</>
);
const renderInactive = () => (
<>
<Text variant="h3" style={styles.notActive}>
{t('tracing:status:heading')}
</Text>
<Spacing s={20} />
<View style={styles.row}>
<Image
style={styles.moduleImage as ImageStyle}
source={IconTracingInactive}
accessibilityIgnoresInvertColors={false}
/>
<Text variant="h1" style={styles.notActive} maxFontSizeMultiplier={3}>
{t('tracing:status:inactive')}
</Text>
</View>
<Spacing s={20} />
<Markdown>{t('tracing:inactiveMessage')}</Markdown>
<Spacing s={20} />
<Text bold maxFontSizeMultiplier={3}>
{t('tracing:turnOn1')}
</Text>
<Spacing s={20} />
<Text bold maxFontSizeMultiplier={3}>
{t('tracing:turnOn2')}
</Text>
<Spacing s={30} />
<GoToSettings />
<Spacing s={40} />
<Markdown>{t('tracing:inactiveMessage1')}</Markdown>
</>
);
const renderPaused = () => (
<>
<Text variant="h3" style={styles.notActive}>
{t('tracing:status:heading')}
</Text>
<Spacing s={20} />
<View style={styles.row}>
<View>
<Image
style={styles.moduleImage as ImageStyle}
source={IconPaused}
accessibilityIgnoresInvertColors={false}
/>
</View>
<View>
<Text variant="h1" style={styles.notActive}>
{t('tracing:paused:title')}
</Text>
</View>
</View>
<Spacing s={20} />
<Text bold color="errorRed">
{t('tracing:paused:reminder')} {format(pauseDate, 'HH:mm')}{' '}
{isToday(pauseDate)
? t('common:today')
: isTomorrow(pauseDate)
? t('common:tomorrow')
: ''}
</Text>
{showSpinner ? (
<View>
<Spacing s={36} />
<ActivityIndicator color={colors.darkGrey} size="large" />
<Spacing s={36} />
</View>
) : (
<Markdown markdownStyles={inactiveMarkdownStyles}>
{t('tracing:paused:text')}
</Markdown>
)}
<Spacing s={20} />
<Button
type="primary"
variant="dark"
rounded
onPress={async () => {
setShowSpinner(true);
await start();
deleteReminder();
setShowSpinner(false);
}}>
{t('tracing:paused:buttonLabel')}
</Button>
</>
);
return (
<ScrollView style={styles.container}>
<ModalHeader
icon={TracingIcon}
closeIcon={CloseIcon}
heading="tracing:heading"
color="validationGreen"
/>
<Spacing s={34} />
<Container center="horizontal">
{hasContact && (
<>
<TouchableWithoutFeedback
onPress={() => navigation.navigate(ScreenNames.closeContact)}>
<Container center="horizontal">
<RoundedBox style={styles.notification}>
<Text variant="h3" color="errorRed">
{t('tracing:notificationTitle')}
</Text>
<Spacing s={10} />
<Markdown markdownStyles={notificationMarkdownStyles}>
{t('tracing:notificationBody')}
</Markdown>
</RoundedBox>
</Container>
</TouchableWithoutFeedback>
<Spacing s={55} />
</>
)}
<Image
source={TracingIllustration}
accessibilityIgnoresInvertColors={false}
/>
<Spacing s={43} />
<Text variant="leader" color="darkGrey" align="center">
{t('tracing:body')}
</Text>
<Spacing s={30} />
<Markdown accessibleLink={t('links:o')}>
{t('tracing:additional', {link: t('links:o')})}
</Markdown>
<Spacing s={34} />
<RoundedBox
style={tracingActive && !paused ? styles.active : undefined}>
{paused
? renderPaused()
: tracingActive
? renderActive()
: renderInactive()}
</RoundedBox>
<Spacing s={20} />
{!paused && tracingActive && (
<Button
type="secondary"
rounded
textColor="validationGreen"
onPress={() => navigation.navigate(ScreenNames.pause)}
style={styles.button}
buttonStyle={styles.buttonStyle}>
I want to pause Tracing
</Button>
)}
</Container>
<Spacing s={120} />
</ScrollView>
);
}
Example #6
Source File: useReadingRank.ts From apps with GNU Affero General Public License v3.0 | 4 votes |
export default function useReadingRank(
disableNewRankPopup?: boolean,
): ReturnType {
const { alerts, loadedAlerts, updateAlerts } = useContext(AlertContext);
const { user, tokenRefreshed, loadedUserFromCache } = useContext(AuthContext);
const [levelUp, setLevelUp] = useState(false);
const [showRankPopup, setShowRankPopup] = useState(false);
const queryClient = useQueryClient();
const { optOutWeeklyGoal } = useContext(SettingsContext);
const [cachedRank, setCachedRank, loadedCache] = usePersistentState<
MyRankData & { userId: string; neverShowRankModal?: boolean }
>(RANK_CACHE_KEY, null);
const neverShowRankModal = cachedRank?.neverShowRankModal;
const queryKey = getRankQueryKey(user);
const { data: remoteRank } = useQuery<MyRankData>(
queryKey,
() =>
request(`${apiUrl}/graphql`, MY_READING_RANK_QUERY, {
id: user.id,
version: 2,
}),
{
enabled: !!user && tokenRefreshed,
refetchOnWindowFocus: false,
},
);
const cacheRank = (
rank: MyRankData = remoteRank,
newNeverShowRankModal = neverShowRankModal,
) =>
setCachedRank({
rank: rank.rank,
reads: rank.reads,
userId: user?.id,
neverShowRankModal: newNeverShowRankModal,
});
const shouldShowRankModal =
showRankPopup &&
!optOutWeeklyGoal &&
checkShouldShowRankModal(
alerts?.rankLastSeen,
cachedRank?.rank?.lastReadTime || remoteRank?.rank?.lastReadTime,
loadedAlerts,
neverShowRankModal,
);
const timeoutRef = useRef<number>();
const visibilityRef = useRef(null);
const updateShownProgress = useCallback(async () => {
if (visibilityRef.current) {
document.removeEventListener('visibilitychange', visibilityRef.current);
}
visibilityRef.current = () => {
timeoutRef.current = window.setTimeout(updateShownProgress, 1000);
};
if (document.visibilityState === 'hidden') {
document.addEventListener('visibilitychange', visibilityRef.current, {
once: true,
});
} else if (cachedRank?.rank.currentRank === remoteRank?.rank.currentRank) {
await cacheRank();
} else {
setLevelUp(true);
}
}, [cachedRank, remoteRank]);
useEffect(() => {
if (!disableNewRankPopup) {
setShowRankPopup(levelUp);
}
}, [levelUp]);
// Cleanup effect to set the unmounting and remove active listeners.
useEffect(
() => () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
if (visibilityRef.current) {
document.removeEventListener('visibilitychange', visibilityRef.current);
}
},
[],
);
// Let the rank update and then show progress animation, slight delay so the user won't miss it
const displayProgress = () => {
timeoutRef.current = window.setTimeout(updateShownProgress, 300);
};
useEffect(() => {
if (remoteRank && loadedCache) {
if (
!cachedRank ||
remoteRank.rank.progressThisWeek < cachedRank.rank.progressThisWeek
) {
/* if there is no cache value or it is not the most updated let's set the cache */
cacheRank();
} else if (cachedRank && !cachedRank.rank.rankLastWeek) {
/*
else if the cache value has data but missing some properties rankLastWeek, let's re-set it
with that, this can mean the user is on their first week, which should see the progress animation
*/
cacheRank();
displayProgress();
} else {
/* else - the cache has pre-existing value so we just need to check if we should display the progress */
displayProgress();
}
}
}, [remoteRank, loadedCache]);
// For anonymous users
useEffect(() => {
if (loadedCache && loadedUserFromCache && tokenRefreshed) {
if (cachedRank?.userId !== user?.id) {
// Reset cache on user change
if (remoteRank) {
cacheRank();
} else if (user) {
setCachedRank(null);
} else {
cacheRank(defaultRank);
}
} else if (!user) {
// Check anonymous progress
let rank = cachedRank ?? defaultRank;
if (rank.rank.lastReadTime) {
if (!isThisISOWeek(rank.rank.lastReadTime)) {
rank = defaultRank;
} else if (rank.rank.readToday && !isToday(rank.rank.lastReadTime)) {
rank.rank.readToday = false;
}
}
queryClient.setQueryData<MyRankData>(queryKey, rank);
}
}
}, [user, tokenRefreshed, loadedUserFromCache, loadedCache]);
return useMemo(
() => ({
isLoading: !cachedRank,
rankLastWeek: cachedRank?.rank.rankLastWeek,
rank: cachedRank?.rank.currentRank,
nextRank: remoteRank?.rank.currentRank,
progress: cachedRank?.rank.progressThisWeek,
tags: cachedRank?.rank.tags,
reads: remoteRank?.reads,
levelUp,
shouldShowRankModal,
confirmLevelUp: (newNeverShowRankModal) => {
setLevelUp(false);
if (user) {
const lastSeen = newNeverShowRankModal ? MAX_DATE : new Date();
updateAlerts({ rankLastSeen: lastSeen });
return cacheRank(remoteRank);
}
// Limit anonymous users to rank zero
const rank = queryClient.setQueryData<MyRankData>(
queryKey,
(currentRank) => ({
rank: { ...currentRank.rank, currentRank: 0 },
reads: currentRank?.reads,
}),
);
return cacheRank(rank, newNeverShowRankModal);
},
}),
[cachedRank, remoteRank, levelUp, shouldShowRankModal, user, queryKey],
);
}
Example #7
Source File: index.tsx From gobarber-project with MIT License | 4 votes |
Dashboard: React.FC = () => {
const { user, signOut } = useAuth();
const [selectedDate, setSelectedDate] = useState(new Date());
const [currentMonth, setCurrentMonth] = useState(new Date());
const [monthAvailability, setMonthAvailability] = useState<
MonthAvailabilityItem[]
>([]);
const [appointments, setAppointments] = useState<Appointments[]>([]);
const handleDateChange = useCallback((day: Date, modifiers: DayModifiers) => {
if (modifiers.available && !modifiers.disabled) {
setSelectedDate(day);
}
}, []);
const handleMonthChange = useCallback((month: Date) => {
setCurrentMonth(month);
}, []);
useEffect(() => {
api
.get(`/providers/${user.id}/month-availability`, {
params: {
year: currentMonth.getFullYear(),
month: currentMonth.getMonth() + 1,
},
})
.then(response => {
setMonthAvailability(response.data);
});
}, [currentMonth, user.id]);
useEffect(() => {
api
.get<Appointments[]>('/appointments/me', {
params: {
year: selectedDate.getFullYear(),
month: selectedDate.getMonth() + 1,
day: selectedDate.getDate(),
},
})
.then(response => {
const appointmentsFormatted = response.data.map(appointment => {
return {
...appointment,
hourFormatted: format(parseISO(appointment.date), 'HH:mm'),
};
});
setAppointments(appointmentsFormatted);
});
}, [selectedDate]);
const disabledDays = useMemo(() => {
const dates = monthAvailability
.filter(monthDay => monthDay.available === false)
.map(monthDay => {
const year = currentMonth.getFullYear();
const month = currentMonth.getMonth();
return new Date(year, month, monthDay.day);
});
return dates;
}, [currentMonth, monthAvailability]);
const selectedDateAsText = useMemo(() => {
return format(selectedDate, "'Dia' dd 'de' MMMM", {
locale: ptBR,
});
}, [selectedDate]);
const selectedWeekDay = useMemo(() => {
return format(selectedDate, 'cccc', {
locale: ptBR,
});
}, [selectedDate]);
const morningAppointments = useMemo(() => {
return appointments.filter(appointment => {
return parseISO(appointment.date).getHours() < 12;
});
}, [appointments]);
const afternoonAppointments = useMemo(() => {
return appointments.filter(appointment => {
return parseISO(appointment.date).getHours() >= 12;
});
}, [appointments]);
const nextAppointment = useMemo(() => {
return appointments.find(appointment =>
isAfter(parseISO(appointment.date), new Date()),
);
}, [appointments]);
return (
<Container>
<Header>
<HeaderContent>
<img src={logo} alt="GoBarber" />
<Profile>
<img src={user.avatar_url} alt={user.name} />
<div>
<span>Bem-vindo,</span>
<Link to="/profile">
<strong>{user.name}</strong>
</Link>
</div>
</Profile>
<button type="button" onClick={signOut}>
<FiPower />
</button>
</HeaderContent>
</Header>
<Content>
<Schedule>
<h1>Horários agendados</h1>
<p>
{isToday(selectedDate) && <span>Hoje</span>}
<span>{selectedDateAsText}</span>
<span>{selectedWeekDay}</span>
</p>
{isToday(selectedDate) && nextAppointment && (
<NextAppointment>
<strong>Agendamento a seguir</strong>
<div>
<img
src={nextAppointment.user.avatar_url}
alt={nextAppointment.user.name}
/>
<strong>{nextAppointment.user.name}</strong>
<span>
<FiClock />
{nextAppointment.hourFormatted}
</span>
</div>
</NextAppointment>
)}
<Section>
<strong>Manhã</strong>
{morningAppointments.length === 0 && (
<p>Nenhum agendamento no horário da manhã</p>
)}
{morningAppointments.map(appointment => (
<Appointment key={appointment.id}>
<span>
<FiClock />
{appointment.hourFormatted}
</span>
<div>
<img
src={appointment.user.avatar_url}
alt={appointment.user.name}
/>
<strong>{appointment.user.name}</strong>
</div>
</Appointment>
))}
</Section>
<Section>
<strong>Tarde</strong>
{afternoonAppointments.length === 0 && (
<p>Nenhum agendamento no horário da tarde</p>
)}
{afternoonAppointments.map(appointment => (
<Appointment key={appointment.id}>
<span>
<FiClock />
{appointment.hourFormatted}
</span>
<div>
<img
src={appointment.user.avatar_url}
alt={appointment.user.name}
/>
<strong>{appointment.user.name}</strong>
</div>
</Appointment>
))}
</Section>
</Schedule>
<Calender>
<DayPicker
weekdaysShort={['D', 'S', 'T', 'Q', 'Q', 'S', 'S']}
fromMonth={new Date()}
disabledDays={[{ daysOfWeek: [0, 6] }, ...disabledDays]}
modifiers={{
available: { daysOfWeek: [1, 2, 3, 4, 5] },
}}
onMonthChange={handleMonthChange}
selectedDays={selectedDate}
onDayClick={handleDateChange}
months={[
'Janeiro',
'Fevereiro',
'Março',
'Abril',
'Maio',
'Junho',
'Julho',
'Agosto',
'Setembro',
'Outubro',
'Novembro',
'Dezembro',
]}
/>
</Calender>
</Content>
</Container>
);
}
Example #8
Source File: index.tsx From GoBarber with MIT License | 4 votes |
Dashboard: React.FC = () => {
const [selectedDate, setSelectedDate] = useState<Date>(new Date());
const [currentMonth, setCurrentMonth] = useState<Date>(new Date());
const [appointments, setAppointments] = useState<ScheduleAppointment[]>([]);
const [monthAvailability, setMonthAvailability] = useState<
MonthAvailabilityItem[]
>([]);
const { user } = useAuth();
useEffect(() => {
api
.get<MonthAvailabilityItem[]>(
`/providers/${user.id}/month-availability`,
{
params: {
year: currentMonth.getFullYear(),
month: currentMonth.getMonth() + 1,
},
},
)
.then((response) => {
setMonthAvailability(response.data);
});
}, [currentMonth, user.id]);
useEffect(() => {
api
.get<ScheduleAppointment[]>('/appointments/me', {
params: {
year: selectedDate.getFullYear(),
month: selectedDate.getMonth() + 1,
day: selectedDate.getDate(),
},
})
.then((response) => {
const appointmentsFormatted = response.data.map((appointment) => {
return {
...appointment,
hourFormatted: format(parseISO(appointment.date), 'HH:mm'),
};
});
setAppointments(appointmentsFormatted);
});
}, [selectedDate]);
const handleDateChange = useCallback((day: Date, modifiers: DayModifiers) => {
if (modifiers.available && !modifiers.disabled) {
setSelectedDate(day);
}
}, []);
const handleMonthChange = useCallback((month: Date) => {
setCurrentMonth(month);
}, []);
const disabledDays = useMemo(() => {
const dates = monthAvailability
.filter((monthDay) => monthDay.available === false)
.map((monthDay) => {
const year = currentMonth.getFullYear();
const month = currentMonth.getMonth();
return new Date(year, month, monthDay.day);
});
return dates;
}, [currentMonth, monthAvailability]);
const selectedDateAsText = useMemo(() => {
return format(selectedDate, "'Dia' dd 'de' MMMM", {
locale: ptBR,
});
}, [selectedDate]);
const selectedWeekDay = useMemo(() => {
return format(selectedDate, 'cccc', {
locale: ptBR,
});
}, [selectedDate]);
const morningAppointments = useMemo(() => {
return appointments.filter((appointment) => {
return parseISO(appointment.date).getHours() < 12;
});
}, [appointments]);
const afternoonAppointments = useMemo(() => {
return appointments.filter((appointment) => {
return parseISO(appointment.date).getHours() >= 12;
});
}, [appointments]);
const nextAppointment = useMemo(() => {
return appointments.find((appointment) =>
isAfter(parseISO(appointment.date), new Date()),
);
}, [appointments]);
return (
<Container>
<Header />
<Content>
<Schedule>
<h1>Horários agendados</h1>
<p>
{isToday(selectedDate) && <span>Hoje</span>}
<span>{selectedDateAsText}</span>
<span>{selectedWeekDay}</span>
</p>
{isToday(selectedDate) && nextAppointment && (
<NextAppointment>
<strong>Agendamento a seguir</strong>
<div>
<img
src={nextAppointment.user.avatar_url}
alt={nextAppointment.id}
/>
<strong>{nextAppointment.user.name}</strong>
<span>
<FiClock />
{nextAppointment.hourFormatted}
</span>
</div>
</NextAppointment>
)}
<Section>
<strong>Manhã</strong>
{morningAppointments.length === 0 && (
<p>Nenhum agendamento marcado nesse período</p>
)}
{morningAppointments.map((appointment) => (
<Appointment key={appointment.id}>
<span>
<FiClock />
{appointment.hourFormatted}
</span>
<div>
<img
src={appointment.user.avatar_url || blankAvatar}
alt={appointment.user.name}
/>
<strong>{appointment.user.name}</strong>
</div>
</Appointment>
))}
</Section>
<Section>
<strong>Tarde</strong>
{afternoonAppointments.length === 0 && (
<p>Nenhum agendamento marcado nesse período</p>
)}
{afternoonAppointments.map((appointment) => (
<Appointment key={appointment.id}>
<span>
<FiClock />
{appointment.hourFormatted}
</span>
<div>
<img
src={appointment.user.avatar_url || blankAvatar}
alt={appointment.user.name}
/>
<strong>{appointment.user.name}</strong>
</div>
</Appointment>
))}
</Section>
</Schedule>
<Calendar>
<DayPicker
weekdaysShort={['D', 'S', 'T', 'Q', 'Q', 'S', 'S']}
fromMonth={new Date()}
selectedDays={selectedDate}
disabledDays={[{ daysOfWeek: [0, 6] }, ...disabledDays]}
modifiers={{
available: { daysOfWeek: [1, 2, 3, 4, 5] },
}}
onDayClick={handleDateChange}
onMonthChange={handleMonthChange}
months={[
'Janeiro',
'Fevereiro',
'Março',
'Abril',
'Maio',
'Junho',
'Julho',
'Agosto',
'Setembro',
'Outubro',
'Novembro',
'Dezembro',
]}
/>
</Calendar>
</Content>
</Container>
);
}
Example #9
Source File: UserBookings.tsx From office-booker with MIT License | 4 votes |
UserBookings: React.FC<RouteComponentProps<{ email: string }>> = (props) => {
// Global state
const { state, dispatch } = useContext(AppContext);
const { user } = state;
// Local state
const [loading, setLoading] = useState(true);
const [selectedUser, setSelectedUser] = useState<User | undefined>();
const [bookings, setBookings] = useState<Booking[] | undefined>();
const [bookingToCancel, setBookingToCancel] = useState<undefined | Booking>();
const [sortedBookings, setSortedBookings] = useState<Booking[] | undefined>();
const [sortBy, setSortBy] = useState<keyof Booking>('date');
const [sortOrder, setSortOrder] = useState<SortOrder>('asc');
// Theme
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
// Effects
useEffect(() => {
if (props.email) {
getBookings({ user: props.email })
.then((data) => {
// Split for previous and upcoming
setBookings(data);
})
.catch((err) => {
// Handle errors
setLoading(false);
dispatch({
type: 'SET_ALERT',
payload: {
message: formatError(err),
color: 'error',
},
});
});
}
}, [props.email, dispatch]);
useEffect(() => {
if (user && !user.permissions.canViewUsers) {
// No permissions - Bounce to home page
navigate('/');
}
}, [user]);
useEffect(() => {
if (user) {
// Get selected user
getUser(props.email || '')
.then((selectedUser) => setSelectedUser(selectedUser))
.catch((err) => {
// Handle errors
setLoading(false);
dispatch({
type: 'SET_ALERT',
payload: {
message: formatError(err),
color: 'error',
},
});
});
}
}, [user, props.email, dispatch]);
useEffect(() => {
if (bookings) {
// Sort it!
setSortedBookings(sortData([...bookings], sortBy, sortOrder));
}
}, [bookings, sortBy, sortOrder]);
useEffect(() => {
if (bookings) {
// Wait for global state to be ready
setLoading(false);
}
}, [bookings]);
// Handlers
const handleSort = (key: keyof Booking) => {
if (key === sortBy) {
setSortOrder(sortOrder === 'desc' ? 'asc' : 'desc');
} else {
setSortBy(key);
}
};
const getAllBookings = useCallback(() => {
if (state.user) {
getBookings({ user: state.user.email })
.then((data) => {
// Split for previous and upcoming
setBookings(data);
})
.catch((err) => {
// Handle errors
setLoading(false);
dispatch({
type: 'SET_ALERT',
payload: {
message: formatError(err),
color: 'error',
},
});
});
}
}, [state.user, dispatch]);
const handleCancelBooking = (booking: Booking) => {
cancelBooking(booking.id, booking.user)
.then(() => {
// Clear selected booking
setBookingToCancel(undefined);
// Retrieve updated bookings
getAllBookings();
// Show confirmation alert
dispatch({
type: 'SET_ALERT',
payload: {
message: 'Booking cancelled',
color: 'success',
},
});
})
.catch((err) =>
dispatch({
type: 'SET_ALERT',
payload: {
message: formatError(err),
color: 'error',
},
})
);
};
// Render
if (!user) {
return null;
}
return (
<AdminLayout currentRoute="users">
<UserBookingsStyles>
{loading || !selectedUser ? (
<Loading />
) : (
<>
<h3>User Bookings</h3>
<Paper square className="table-container">
<h4>{selectedUser.email}</h4>
<TableContainer className="table">
<Table>
<TableHead>
<TableRow>
<TableCell className="table-header">
<TableSortLabel
active={sortBy === 'office'}
direction={sortOrder}
onClick={() => handleSort('office')}
>
Office
</TableSortLabel>
</TableCell>
<TableCell className="table-header">
<TableSortLabel
active={sortBy === 'date'}
direction={sortOrder}
onClick={() => handleSort('date')}
>
Date
</TableSortLabel>
</TableCell>
<TableCell className="table-header">
<TableSortLabel
active={sortBy === 'parking'}
direction={sortOrder}
onClick={() => handleSort('parking')}
>
Parking
</TableSortLabel>
</TableCell>
<TableCell />
</TableRow>
</TableHead>
<TableBody>
{sortedBookings && sortedBookings.length > 0 ? (
sortedBookings.map((booking, index) => {
const parsedDate = parseISO(booking.date);
return (
<TableRow key={index}>
<TableCell>{booking.office.name}</TableCell>
<TableCell>
{' '}
{format(
parse(booking.date, 'yyyy-MM-dd', new Date(), DATE_FNS_OPTIONS),
'do LLLL yyyy',
DATE_FNS_OPTIONS
)}
</TableCell>
<TableCell>{booking.parking ? 'Yes' : 'No'}</TableCell>
{isToday(parsedDate) || !isPast(parsedDate) ? (
<TableCell align="right">
<div className="btn-container">
<OurButton
type="submit"
variant="contained"
color="secondary"
size="small"
onClick={() => setBookingToCancel(booking)}
>
Cancel
</OurButton>
</div>
</TableCell>
) : (
<TableCell />
)}
</TableRow>
);
})
) : (
<TableRow>
<TableCell>No bookings found</TableCell>
<TableCell />
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
</Paper>
</>
)}
{bookingToCancel && (
<Dialog fullScreen={fullScreen} open={true} onClose={() => setBookingToCancel(undefined)}>
<DialogTitle>{'Are you sure you want to cancel this booking?'}</DialogTitle>
<DialogContent>
<DialogContentText>
Booking for <strong>{bookingToCancel.user}</strong> on{' '}
<strong>{format(parseISO(bookingToCancel.date), 'do LLLL')}</strong> for{' '}
<strong>{bookingToCancel.office.name}</strong>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={() => setBookingToCancel(undefined)} color="primary" autoFocus>
No
</Button>
<Button
autoFocus
onClick={() => handleCancelBooking(bookingToCancel)}
color="primary"
>
Yes
</Button>
</DialogActions>
</Dialog>
)}
</UserBookingsStyles>
</AdminLayout>
);
}