Skip to content

Commit

Permalink
Merge pull request #327 from code4romania/bulk-318/#5-redirect-to-vol…
Browse files Browse the repository at this point in the history
…unteer-profile

feat: open error bottom sheet on attend event
  • Loading branch information
luciatugui authored Jul 26, 2024
2 parents e0760c7 + c5c7269 commit 926def9
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 69 deletions.
7 changes: 6 additions & 1 deletion mobile/src/assets/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,11 @@
"going": "Particip",
"not_going": "Not participating",
"cancel": "Withdraw reply"
},
"error_modal": {
"title": "Ups!",
"description": "You did not fill in the data for your volunteer profile. Fill it out in order to be able to attend the event.",
"action_btn_label": "Complete data"
}
},
"activity_logs": {
Expand All @@ -528,7 +533,7 @@
},
"error_modal": {
"title": "Ups!",
"description": "You did not fill in your identification data in your Volunteer profile. Fill it out in order to be able to log volunteering hours.",
"description": "You did not fill in the data for your volunteer profile. Fill it out in order to be able to log volunteering hours.",
"action_btn_label": "Complete data"
}
},
Expand Down
5 changes: 5 additions & 0 deletions mobile/src/assets/locales/ro/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,11 @@
"going": "Particip",
"not_going": "Nu particip",
"cancel": "Retrage răspuns"
},
"error_modal": {
"title": "Ups!",
"description": "Încă nu ți-ai completat profilul de voluntar. Adaugă datele a putea participa la eveniment.",
"action_btn_label": "Completează datele"
}
},
"activity_logs": {
Expand Down
246 changes: 178 additions & 68 deletions mobile/src/screens/Event.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React, { useEffect, useMemo, useRef } from 'react';
import PageLayout from '../layouts/PageLayout';
import { Icon, Text, useTheme } from '@ui-kitten/components';
import { StyleSheet } from 'react-native';
Expand Down Expand Up @@ -26,16 +26,42 @@ import ImageWithPreload from '../components/ImageWithPreload';
import { ALLOW_FONT_SCALLING } from '../common/constants/constants';
import { formatEventDate } from '../common/utils/event.helper';
import { usePaddingTop } from '../hooks/usePaddingTop';
import { useUserProfile } from '../store/profile/profile.selector';
import BottomSheet from '@gorhom/bottom-sheet';
import { renderBackdrop } from '../components/BottomSheet';
import { useReducedMotion } from 'react-native-reanimated';
import { SvgXml } from 'react-native-svg';
import upsIcon from '../assets/svg/ups-icon';
import Paragraph from '../components/Paragraph';
import Button from '../components/Button';
import InlineLink from '../components/InlineLink';
import { useSwitchOrganizationMutation } from '../services/organization/organization.service';

const Event = ({ navigation, route }: any) => {
const { t } = useTranslation('event');

const theme = useTheme();
const paddingTop = usePaddingTop();

const { userProfile } = useUserProfile();
const { eventId } = route.params;

const { event } = useEvent();
// get the current event's organization from the list of the user's organizations
const currentEventOrganization = useMemo(
() =>
userProfile?.myOrganizations.find(
//TODO: use the organization 'id' instead of 'name' when the backend returns it
(organization) => organization.name === event?.organizationName,
),
[userProfile, event],
);
const { setActiveOrganization } = useStore();
const { mutate: switchOrganization } = useSwitchOrganizationMutation();

// bottom sheet ref
const bottomSheetRef = useRef<BottomSheet>(null);
// bottom sheet snap points
const snapPoints = useMemo(() => [1, 410], []);
const reducedMotion = useReducedMotion();

const { declineEvent, canceRsvp, joinEvent } = useStore();

Expand Down Expand Up @@ -71,11 +97,18 @@ const Event = ({ navigation, route }: any) => {
},
{
onSuccess: going ? joinEvent : declineEvent,
onError: (error: any) =>
onError: (error: any) => {
//if we don't have a volunteerProfileId for this organization -> open error bottom sheet that will redirect the user to the volunteer profile page
if (userProfile && event) {
if (!currentEventOrganization?.volunteerProfileId) {
return bottomSheetRef.current?.expand();
}
}
Toast.show({
type: 'error',
text1: `${InternalErrors.EVENT_ERRORS.getError(error.response?.data.code_error)}`,
}),
});
},
},
);
}
Expand Down Expand Up @@ -107,72 +140,129 @@ const Event = ({ navigation, route }: any) => {
}
};

const onRedirectToVolunteerProfile = () => {
//check if the organization for the current event is the active organization for the user
if (userProfile && currentEventOrganization) {
if (userProfile.activeOrganization?.id === currentEventOrganization.id) {
//redirect to volunteer profile
onCloseBottomSheet();
navigation.navigate('volunteer-profile');
} else {
//switch the active organization for the user to the current event's organization and redirect to volunteer-profile
onCloseBottomSheet();
setActiveOrganization(currentEventOrganization!);
switchOrganization({
organizationId: currentEventOrganization.id,
});
navigation.navigate('volunteer-profile');
}
}
};

const onCloseBottomSheet = () => {
bottomSheetRef.current?.close();
};

return (
<PageLayout
title={t('details')}
headerStyle={{ paddingTop }}
onBackButtonPress={navigation.goBack}
actionsOptions={{
loading: isLoadingEvent || isResponding || isCancelingRsvp,
primaryActionLabel:
event?.volunteerStatus !== EventVolunteerStatus.NO_RESPONSE
? `${t('rsvp.cancel')}`
: `${t('rsvp.going')}`,
onPrimaryActionButtonClick:
event?.volunteerStatus !== EventVolunteerStatus.NO_RESPONSE
? onCancelRsvpResponse
: onRsvpReponsePress.bind(null, true),
primaryBtnType:
event?.volunteerStatus !== EventVolunteerStatus.NO_RESPONSE
? ButtonType.DANGER
: ButtonType.PRIMARY,
...(event?.volunteerStatus === EventVolunteerStatus.NO_RESPONSE && !isResponding
? {
secondaryActionLink: `${t('rsvp.not_going')}`,
onSecondaryActionButtonClick: onRsvpReponsePress.bind(null, false),
}
: {}),
helperText: mapNumberOfPersonsToHelper(),
}}
>
{isLoadingEvent && <EventSkeleton />}
{event && !isLoadingEvent && (
<FormLayout>
{event.poster ? (
<ImageWithPreload source={event.poster} styles={styles.image} />
) : (
<View style={{ ...styles.image, backgroundColor: theme['cool-gray-100'] }}>
<Icon
name="calendar"
style={{ ...styles.imagePlaceholder, color: theme['cool-gray-500'] }}
/>
</View>
)}
<OrganizationIdentity
uri={event.organizationLogo || ''}
name={event.organizationName || ''}
/>
<ReadOnlyElement
label={t('date')}
value={formatEventDate(event.startDate, event.endDate)}
/>
<ReadOnlyElement label={t('name')} value={event.name} />
<ReadOnlyElement label={t('target')} value={mapEventType(event)} />
<ReadOnlyElement label={t('location')} value={event.location} />
<ReadOnlyElement label={t('description')} value={event.description} />
<View style={styles.container}>
<Text allowFontScaling={ALLOW_FONT_SCALLING} category="c1" appearance="hint">{`${t(
'tasks',
)}`}</Text>
<View style={styles.taskContainer}>
{event.tasks.map((task) => (
<TaskPill key={task.id} label={task.name} />
))}
<>
<PageLayout
title={t('details')}
headerStyle={{ paddingTop }}
onBackButtonPress={navigation.goBack}
actionsOptions={{
loading: isLoadingEvent || isResponding || isCancelingRsvp,
primaryActionLabel:
event?.volunteerStatus !== EventVolunteerStatus.NO_RESPONSE
? `${t('rsvp.cancel')}`
: `${t('rsvp.going')}`,
onPrimaryActionButtonClick:
event?.volunteerStatus !== EventVolunteerStatus.NO_RESPONSE
? onCancelRsvpResponse
: onRsvpReponsePress.bind(null, true),
primaryBtnType:
event?.volunteerStatus !== EventVolunteerStatus.NO_RESPONSE
? ButtonType.DANGER
: ButtonType.PRIMARY,
...(event?.volunteerStatus === EventVolunteerStatus.NO_RESPONSE && !isResponding
? {
secondaryActionLink: `${t('rsvp.not_going')}`,
onSecondaryActionButtonClick: onRsvpReponsePress.bind(null, false),
}
: {}),
helperText: mapNumberOfPersonsToHelper(),
}}
>
{isLoadingEvent && <EventSkeleton />}
{event && !isLoadingEvent && (
<FormLayout>
{event.poster ? (
<ImageWithPreload source={event.poster} styles={styles.image} />
) : (
<View style={{ ...styles.image, backgroundColor: theme['cool-gray-100'] }}>
<Icon
name="calendar"
style={{ ...styles.imagePlaceholder, color: theme['cool-gray-500'] }}
/>
</View>
)}
<OrganizationIdentity
uri={event.organizationLogo || ''}
name={event.organizationName || ''}
/>
<ReadOnlyElement
label={t('date')}
value={formatEventDate(event.startDate, event.endDate)}
/>
<ReadOnlyElement label={t('name')} value={event.name} />
<ReadOnlyElement label={t('target')} value={mapEventType(event)} />
<ReadOnlyElement label={t('location')} value={event.location} />
<ReadOnlyElement label={t('description')} value={event.description} />
<View style={styles.container}>
<Text allowFontScaling={ALLOW_FONT_SCALLING} category="c1" appearance="hint">{`${t(
'tasks',
)}`}</Text>
<View style={styles.taskContainer}>
{event.tasks.map((task) => (
<TaskPill key={task.id} label={task.name} />
))}
</View>
</View>
</FormLayout>
)}
</PageLayout>
{/* error bottom sheet -> displayed when the user tries to attend the event but doesn't have a volunteer profile for the event's organization */}
<BottomSheet
backdropComponent={renderBackdrop}
ref={bottomSheetRef}
index={-1}
snapPoints={snapPoints}
animateOnMount={reducedMotion ? false : true}
>
<View style={styles.bottomSheetContainer}>
<SvgXml xml={upsIcon} height={100} width={100} />
<View style={styles.textContainer}>
<Text allowFontScaling={ALLOW_FONT_SCALLING} category="h1">
{`${t('error_modal.title')}`}
</Text>
<Paragraph style={styles.bottomSheetParagraph}>
{`${t('error_modal.description')}`}
</Paragraph>
</View>
<View style={styles.buttonsContainer}>
<Button
label={`${t('error_modal.action_btn_label')}`}
status={'primary'}
onPress={onRedirectToVolunteerProfile}
/>
<InlineLink
label={t('general:back')}
style={{ color: theme['cool-gray-700'] }}
onPress={onCloseBottomSheet}
/>
</View>
</FormLayout>
)}
</PageLayout>
</View>
</BottomSheet>
</>
);
};

Expand All @@ -195,4 +285,24 @@ const styles = StyleSheet.create({
gap: 8,
},
imagePlaceholder: { width: 48, height: 48 },
bottomSheetContainer: {
flex: 1,
alignItems: 'center',
gap: 24,
paddingVertical: 24,
paddingHorizontal: 20,
},
textContainer: {
gap: 4,
alignItems: 'center',
justifyContent: 'flex-end',
},
bottomSheetParagraph: {
textAlign: 'center',
},
buttonsContainer: {
gap: 16,
justifyContent: 'center',
alignItems: 'center',
},
});

0 comments on commit 926def9

Please sign in to comment.