diff --git a/src/actions.ts b/src/actions.ts index e543434..063cf11 100644 --- a/src/actions.ts +++ b/src/actions.ts @@ -1,3 +1,5 @@ +import { UserType } from './types/data'; + const LOGIN_REQUEST = 'LOGIN_REQUEST'; const LOGIN_SUCCESS = 'LOGIN_SUCCESS'; const LOGIN_FAILURE = 'LOGIN_FAILURE'; @@ -8,9 +10,6 @@ const USER_DATA_FAILURE = 'USER_DATA_FAILURE'; const REGISTER_USER_REQUEST = 'REGISTER_USER_REQUEST'; const REGISTER_USER_SUCCESS = 'REGISTER_USER_SUCCESS'; const REGISTER_USER_FAILURE = 'REGISTER_USER_FAILURE'; -const MEMBERSHIP_CHARGE_REQUEST = 'MEMBERSHIP_CHARGE_REQUEST'; -const MEMBERSHIP_CHARGE_SUCCESS = 'MEMBERSHIP_CHARGE_SUCCESS'; -const MEMBERSHIP_CHARGE_FAILURE = 'MEMBERSHIP_CHARGE_FAILURE'; function loginRequest() { return { @@ -26,7 +25,7 @@ function loginSuccess(username: string, token: string) { }; } -function loginFailure(loginError) { +function loginFailure(loginError: string) { return { type: LOGIN_FAILURE, loginError, @@ -45,14 +44,14 @@ function userDataRequest() { }; } -function userDataSuccess(data) { +function userDataSuccess(data: UserType) { return { type: USER_DATA_SUCCESS, data, }; } -function userDataFailure(userError) { +function userDataFailure(userError: string) { return { type: USER_DATA_FAILURE, userError, @@ -65,38 +64,19 @@ function registerUserRequest() { }; } -function registerUserSuccess(data) { +function registerUserSuccess(data: UserType) { return { type: REGISTER_USER_SUCCESS, data, }; } -function registerUserFailure(registerError) { +function registerUserFailure(registerError: Record) { return { type: REGISTER_USER_FAILURE, registerError, }; } -function membershipChargeRequest() { - return { - type: MEMBERSHIP_CHARGE_REQUEST, - }; -} - -function membershipChargeSuccess(data) { - return { - type: MEMBERSHIP_CHARGE_SUCCESS, - data, - }; -} - -function membershipChargeFailure(chargeError) { - return { - type: MEMBERSHIP_CHARGE_FAILURE, - chargeError, - }; -} export { /* Login */ @@ -123,11 +103,4 @@ export { registerUserSuccess, REGISTER_USER_FAILURE, registerUserFailure, - /* Charge */ - MEMBERSHIP_CHARGE_REQUEST, - membershipChargeRequest, - MEMBERSHIP_CHARGE_SUCCESS, - membershipChargeSuccess, - MEMBERSHIP_CHARGE_FAILURE, - membershipChargeFailure, }; diff --git a/src/api.ts b/src/api.ts index 0adf7a7..adc6891 100644 --- a/src/api.ts +++ b/src/api.ts @@ -8,9 +8,6 @@ import { userDataFailure, userDataRequest, userDataSuccess, - membershipChargeFailure, - membershipChargeRequest, - membershipChargeSuccess, } from './actions'; import type { UserRegisterFormValues } from './modules/register/useUserRegister'; import { AppDispatch } from './reduxStore'; @@ -118,41 +115,6 @@ export function requestRegisterUser({ firstName, lastName, email, phoneNumber, p }; } -export function requestMembershipCharge(authToken: string, stripeToken: string, membershipType: string) { - return (dispatch: AppDispatch) => { - dispatch(membershipChargeRequest()); - - return fetchWithTimeout(`${process.env.EXPO_PUBLIC_DUSKEN_API_URL}/api/membership/charge/`, { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - Authorization: `Token ${authToken}`, - }, - body: JSON.stringify({ - stripe_token: stripeToken, - membership_type: membershipType, - payment_method: 'app', - }), - }) - .then((response) => response.json().then((json) => ({ json, response }))) - .then(({ json, response }) => { - if (response.ok === false) { - return Promise.reject(json); - } - return json; - }) - .then( - (data) => { - dispatch(membershipChargeSuccess(data)); - }, - (data) => { - dispatch(membershipChargeFailure(data.detail || 'Kunne ikke belaste bankkortet, prøv igjen')); - }, - ); - }; -} - /** Create a stripe payment sheet. Note that this is not using redux */ export async function requestStripePaymentSheet(authToken: string, membershipType: string) { const body = JSON.stringify({ diff --git a/src/components/FormErrors.tsx b/src/components/FormErrors.tsx index 1a2cc29..8fcf5ee 100644 --- a/src/components/FormErrors.tsx +++ b/src/components/FormErrors.tsx @@ -2,7 +2,8 @@ import { Alert, HStack } from 'native-base'; import React from 'react'; import { Text } from 'react-native'; -const FormErrors = ({ errors }) => { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const FormErrors = ({ errors }: { errors: Record }) => { if (!Object.keys(errors).length || !['non_field_errors', 'detail'].some((errorField) => errorField in errors)) { return null; } diff --git a/src/components/FormInput.tsx b/src/components/FormInput.tsx index 8baa9db..91e6e81 100644 --- a/src/components/FormInput.tsx +++ b/src/components/FormInput.tsx @@ -41,7 +41,7 @@ const FormInput = ({ /> {fieldError && ( }> - {fieldError.message.toString()} + {fieldError.message?.toString()} )} diff --git a/src/hooks.tsx b/src/hooks.tsx index 664f749..479c9e0 100644 --- a/src/hooks.tsx +++ b/src/hooks.tsx @@ -6,8 +6,8 @@ import { useDispatch, useSelector, useStore } from 'react-redux'; import type { AppDispatch, AppStore, RootState } from './reduxStore'; -export function usePrevious(value) { - const ref = useRef(); +export function usePrevious(value: T): T | undefined { + const ref = useRef(); // Store current value in ref useEffect(() => { @@ -23,7 +23,7 @@ export const useDeepLinking = () => { const { handleURLCallback } = useStripe(); const handleDeepLink = useCallback( - async (url) => { + async (url: string | null) => { if (!url) { return; } diff --git a/src/modules/about/About.tsx b/src/modules/about/About.tsx index 73f1a4a..9742628 100644 --- a/src/modules/about/About.tsx +++ b/src/modules/about/About.tsx @@ -21,10 +21,11 @@ const CHATEAU_NEUF_ADDRESS = 'Det Norske Studentersamfund, Slemdalsveien 15, 036 const openFacebook = () => { /* Ref: https://stackoverflow.com/questions/4810803/open-facebook-page-from-android-app */ - const url = Platform.select({ - ios: 'fb://page/?id=23664032291', - android: 'fb://page/23664032291/', - }); + const url = + Platform.select({ + ios: 'fb://page/?id=23664032291', + android: 'fb://page/23664032291/', + }) || ''; Linking.canOpenURL(url) .then((supported) => { if (!supported) { @@ -36,10 +37,11 @@ const openFacebook = () => { }; const openInstagram = () => { - const url = Platform.select({ - ios: 'instagram://user?username=studentersamfundet', - android: 'https://instagram.com/_u/studentersamfundet', - }); + const url = + Platform.select({ + ios: 'instagram://user?username=studentersamfundet', + android: 'https://instagram.com/_u/studentersamfundet', + }) || ''; Linking.canOpenURL(url) .then((supported) => { @@ -52,10 +54,11 @@ const openInstagram = () => { }; const openMap = () => { - const url = Platform.select({ - ios: `comgooglemaps://?q=${CHATEAU_NEUF_ADDRESS}`, - android: `https://www.google.com/maps/search/?api=1&query=${CHATEAU_NEUF_ADDRESS}`, - }); + const url = + Platform.select({ + ios: `comgooglemaps://?q=${CHATEAU_NEUF_ADDRESS}`, + android: `https://www.google.com/maps/search/?api=1&query=${CHATEAU_NEUF_ADDRESS}`, + }) || ''; Linking.canOpenURL(url) .then((supported) => { if (!supported) { diff --git a/src/modules/events/EventDetail.tsx b/src/modules/events/EventDetail.tsx index db5f8e6..f537bee 100644 --- a/src/modules/events/EventDetail.tsx +++ b/src/modules/events/EventDetail.tsx @@ -69,10 +69,11 @@ const onFacebookUrlPress = (link: string) => { if (matches && matches.length) { iosURL = `fb://event/?id=${matches[1]}`; } - const url = Platform.select({ - ios: iosURL, - android: link, - }); + const url = + Platform.select({ + ios: iosURL, + android: link, + }) || ''; Linking.canOpenURL(url) .then((supported) => { if (!supported) { diff --git a/src/modules/events/EventList.tsx b/src/modules/events/EventList.tsx index 9a25af9..6a623e7 100644 --- a/src/modules/events/EventList.tsx +++ b/src/modules/events/EventList.tsx @@ -6,6 +6,7 @@ import { Button } from 'react-native-ui-lib'; import 'moment/locale/nb'; import theme from 'src/theme'; +import { EventType } from 'src/types/data'; import useEventList from './useEventList'; @@ -15,7 +16,7 @@ const formatTime = (time: string) => { return moment(time).format('llll'); }; -const renderSectionHeader = ({ section }) => ( +const renderSectionHeader = ({ section }: { section: { title: string } }) => ( {section.title} @@ -25,7 +26,7 @@ const Header = () => ; const EventList = () => { const { eventsSectioned, refreshing, handleRefresh, handleLoadMore, showEvent, error, loading } = useEventList(); - const renderItem = ({ item }) => ( + const renderItem = ({ item }: { item: EventType }) => ( { showEvent(item); @@ -77,7 +78,7 @@ const EventList = () => { sections={eventsSectioned} renderItem={renderItem} renderSectionHeader={renderSectionHeader} - keyExtractor={(item) => item.id} + keyExtractor={(item: EventType) => item.id} refreshing={refreshing} onRefresh={handleRefresh} onEndReached={handleLoadMore} diff --git a/src/modules/events/useEventList.tsx b/src/modules/events/useEventList.tsx index fb68ea6..3b410f1 100644 --- a/src/modules/events/useEventList.tsx +++ b/src/modules/events/useEventList.tsx @@ -8,25 +8,28 @@ import { fetchWithTimeout } from 'src/utils'; moment.locale('nb'); -const formatDate = (time) => { +const formatDate = (time: string) => { const m = moment(time); return moment().year() === m.year() ? m.format('dddd D. MMMM') : m.format('ll'); }; - +type SectionedEvents = { + data: EventType[]; + title: string; +}; /* Ref: https://medium.com/react-native-development/how-to-use-the-flatlist-component-react-native-basics-92c482816fe6 */ const useEventList = () => { const { navigate } = useNavigation(); const [loading, setLoading] = useState(false); - const [events, setEvents] = useState([]); - const [eventsSectioned, setEventsSectioned] = useState([]); + const [events, setEvents] = useState([]); + const [eventsSectioned, setEventsSectioned] = useState([]); const [page, setPage] = useState(1); const [totalPages, setTotalPages] = useState(0); - const [error, setError] = useState(null); + const [error, setError] = useState(null); const [refreshing, setRefreshing] = useState(false); - const toSectionFormat = (freshEvents) => { - const sectioned = {}; + const toSectionFormat = (freshEvents: EventType[]) => { + const sectioned: Record = {}; freshEvents.forEach((event) => { const title = formatDate(event.start_time); if (title in sectioned) { @@ -62,7 +65,7 @@ const useEventList = () => { let eventData; try { const res = await fetchWithTimeout(url); - setTotalPages(parseInt(res.headers.get('x-wp-totalpages'), 10)); + setTotalPages(parseInt(res.headers.get('x-wp-totalpages') || '0', 10)); eventData = await res.json(); } catch (err) { setError(err); diff --git a/src/modules/membership/Proof.tsx b/src/modules/membership/Proof.tsx index 0fc615c..16b27b5 100644 --- a/src/modules/membership/Proof.tsx +++ b/src/modules/membership/Proof.tsx @@ -75,14 +75,14 @@ interface PurchaseButtonProps { paymentLoading: boolean; isLoadingMembershipType: boolean; membershipPrice: number; - onChargePress: () => void; + onPurchasePress: () => void; } const PurchaseButton = ({ user, paymentLoading, isLoadingMembershipType, - onChargePress, + onPurchasePress, membershipPrice, }: PurchaseButtonProps) => { if (user.is_member) { @@ -93,7 +93,7 @@ const PurchaseButton = ({ {paymentLoading && }