diff --git a/src/Navigation.tsx b/src/Navigation.tsx
index 2bc5048..2f75d50 100644
--- a/src/Navigation.tsx
+++ b/src/Navigation.tsx
@@ -9,6 +9,7 @@ import EventDetail from 'src/modules/events/EventDetail';
import EventList from 'src/modules/events/EventList';
import Login from 'src/modules/login/Login';
import Membership from 'src/modules/membership/Membership';
+import UserDelete from 'src/modules/membership/UserDelete';
import UserRegister from 'src/modules/register/UserRegister';
import theme from 'src/theme';
import type { EventStackParamList, HomeTabParamList, UserStackParamList } from 'src/types/navigation';
@@ -54,6 +55,13 @@ const UserStackScreen = () => (
title: 'Bli medlem',
}}
/>
+
);
diff --git a/src/actions.ts b/src/actions.ts
index 063cf11..d03846a 100644
--- a/src/actions.ts
+++ b/src/actions.ts
@@ -10,6 +10,9 @@ 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 DELETE_USER_REQUEST = 'DELETE_USER_REQUEST';
+const DELETE_USER_SUCCESS = 'DELETE_USER_SUCCESS';
+const DELETE_USER_FAILURE = 'DELETE_USER_FAILURE';
function loginRequest() {
return {
@@ -78,6 +81,25 @@ function registerUserFailure(registerError: Record) {
};
}
+function deleteUserRequest() {
+ return {
+ type: DELETE_USER_REQUEST,
+ };
+}
+
+function deleteUserSuccess() {
+ return {
+ type: DELETE_USER_SUCCESS,
+ };
+}
+
+function deleteUserFailure(deleteUserError: Record) {
+ return {
+ type: DELETE_USER_FAILURE,
+ deleteUserError,
+ };
+}
+
export {
/* Login */
LOGIN_REQUEST,
@@ -103,4 +125,11 @@ export {
registerUserSuccess,
REGISTER_USER_FAILURE,
registerUserFailure,
+ /* Delete */
+ DELETE_USER_REQUEST,
+ deleteUserRequest,
+ DELETE_USER_SUCCESS,
+ deleteUserSuccess,
+ DELETE_USER_FAILURE,
+ deleteUserFailure,
};
diff --git a/src/api.ts b/src/api.ts
index 331d897..43ae88a 100644
--- a/src/api.ts
+++ b/src/api.ts
@@ -8,6 +8,9 @@ import {
userDataFailure,
userDataRequest,
userDataSuccess,
+ deleteUserFailure,
+ deleteUserSuccess,
+ deleteUserRequest,
} from './actions';
import type { UserRegisterFormValues } from './modules/register/useUserRegister';
import { AppDispatch } from './reduxStore';
@@ -116,6 +119,29 @@ export function requestRegisterUser({ first_name, last_name, email, phone_number
};
}
+export function requestDeleteUser(authToken: string) {
+ return (dispatch: AppDispatch) => {
+ dispatch(deleteUserRequest());
+
+ return fetchWithTimeout(`${process.env.EXPO_PUBLIC_DUSKEN_API_URL}/api/me/delete/`, {
+ method: 'DELETE',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ Authorization: `Token ${authToken}`,
+ },
+ }).then((response) => {
+ if (!response.ok) {
+ return response.json().then((json) => {
+ dispatch(deleteUserFailure(json || { non_field_errors: ['Kunne ikke slette bruker, prøv igjen'] }));
+ });
+ }
+ dispatch(deleteUserSuccess());
+ return {};
+ });
+ };
+}
+
/** 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/modules/membership/Membership.tsx b/src/modules/membership/Membership.tsx
index 7cbcfc0..b534a99 100644
--- a/src/modules/membership/Membership.tsx
+++ b/src/modules/membership/Membership.tsx
@@ -9,8 +9,15 @@ import Proof from './Proof';
import useMembership from './useMembership';
const Membership = () => {
- const { isFetchingUserData, onRegisterPress, onLoginPress, onLogoutPress, isAuthenticated, fetchUser } =
- useMembership();
+ const {
+ isFetchingUserData,
+ onRegisterPress,
+ onLoginPress,
+ onLogoutPress,
+ onDeletePress,
+ isAuthenticated,
+ fetchUser,
+ } = useMembership();
if (isFetchingUserData) {
return (
@@ -23,7 +30,12 @@ const Membership = () => {
if (isAuthenticated) {
return (
<>
-
+
>
);
diff --git a/src/modules/membership/Proof.tsx b/src/modules/membership/Proof.tsx
index 1d37617..bb8c8be 100644
--- a/src/modules/membership/Proof.tsx
+++ b/src/modules/membership/Proof.tsx
@@ -144,8 +144,9 @@ interface ProofProps {
onLogoutPress: () => void;
fetchUser: () => void;
isFetchingUserData: boolean;
+ onDeletePress: () => void;
}
-const Proof = ({ onLogoutPress, fetchUser, isFetchingUserData }: ProofProps) => {
+const Proof = ({ onLogoutPress, fetchUser, isFetchingUserData, onDeletePress }: ProofProps) => {
const CONFETTI_TIMEOUT = 15000;
const confettiRef = useRef(null);
const { paymentLoading, isLoadingMembershipType, onPurchasePress, membershipPrice, toast, setToast, user } = useProof(
@@ -203,6 +204,9 @@ const Proof = ({ onLogoutPress, fetchUser, isFetchingUserData }: ProofProps) =>
Logg ut
+
{
+ const [value, onChangeText] = React.useState('');
+ const user = useAppSelector((state) => state.user);
+ const { onPress, isDeletingUser, deleteUserError } = useUserDelete();
+
+ if (!user) {
+ return null;
+ }
+
+ const isDisabled = !isDeletingUser && value !== user.username;
+
+ return (
+
+
+ Slett meg
+
+ Dette sletter kontoen med brukernavn {user.username} inkludert all tilknyttet
+ persondata for alltid.
+
+ Skriv inn brukernavnet ditt for å fortsette.
+ onChangeText(text)}
+ value={value}
+ style={styles.input}
+ />
+ {deleteUserError && }
+
+ {isDeletingUser && }
+
+
+ );
+};
+
+export default UserDelete;
+
+const styles = StyleSheet.create({
+ paragraph: {
+ textAlign: 'center',
+ fontSize: 16,
+ color: theme.colors.neufBlack,
+ paddingBottom: 10,
+ lineHeight: 25,
+ },
+ bold: {
+ fontWeight: 'bold',
+ },
+ deleteButton: {
+ marginTop: 16,
+ marginBottom: 16,
+ backgroundColor: theme.colors.danger,
+ },
+ deleteButtonDisabled: {
+ marginTop: 16,
+ marginBottom: 16,
+ backgroundColor: theme.colors.neufGray,
+ },
+ whiteText: {
+ color: theme.colors.neufWhite,
+ },
+ disabledText: {
+ opacity: 0.5,
+ },
+ headerTitle: {
+ textAlign: 'center',
+ fontWeight: 'bold',
+ fontSize: 20,
+ color: theme.colors.neufBlack,
+ paddingVertical: 10,
+ lineHeight: 25,
+ },
+ input: {
+ height: 40,
+ borderColor: 'gray',
+ borderWidth: 1,
+ margin: 10,
+ padding: 10,
+ },
+});
diff --git a/src/modules/membership/useMembership.tsx b/src/modules/membership/useMembership.tsx
index 2b8114a..ff2123a 100644
--- a/src/modules/membership/useMembership.tsx
+++ b/src/modules/membership/useMembership.tsx
@@ -19,6 +19,7 @@ const useMembership = () => {
};
const onRegisterPress = () => navigation.navigate('UserStack', { screen: 'UserRegister' });
const onLoginPress = () => navigation.navigate('UserStack', { screen: 'Login' });
+ const onDeletePress = () => navigation.navigate('UserStack', { screen: 'UserDelete' });
const fetchUser = useCallback(() => {
dispatch(requestUserData(userToken || ''));
}, [dispatch, userToken]);
@@ -35,6 +36,7 @@ const useMembership = () => {
userToken,
onLogoutPress,
onRegisterPress,
+ onDeletePress,
onLoginPress,
fetchUser,
};
diff --git a/src/modules/membership/useUserDelete.tsx b/src/modules/membership/useUserDelete.tsx
new file mode 100644
index 0000000..4db60ad
--- /dev/null
+++ b/src/modules/membership/useUserDelete.tsx
@@ -0,0 +1,32 @@
+import { useNavigation } from '@react-navigation/native';
+import { useEffect } from 'react';
+
+import { requestDeleteUser } from 'src/api';
+import { useAppDispatch, useAppSelector, usePrevious } from 'src/hooks';
+
+const useUserDelete = () => {
+ const dispatch = useAppDispatch();
+ const navigation = useNavigation();
+ const isAuthenticated = useAppSelector((store) => store.isAuthenticated);
+ const isAuthenticatedPrev = usePrevious(isAuthenticated);
+ const userToken = useAppSelector((store) => store.userToken);
+ const isDeletingUser = useAppSelector((store) => store.isDeletingUser);
+ const deleteUserError = useAppSelector((store) => store.deleteUserError);
+
+ const onPress = () => {
+ dispatch(requestDeleteUser(userToken || ''));
+ };
+
+ useEffect(() => {
+ if (isAuthenticatedPrev !== isAuthenticated && !isAuthenticated) {
+ navigation.navigate('UserStack', { screen: 'Membership' });
+ }
+ }, [isAuthenticatedPrev, isAuthenticated, navigation]);
+
+ return {
+ onPress,
+ isDeletingUser,
+ deleteUserError,
+ };
+};
+export default useUserDelete;
diff --git a/src/reducers.ts b/src/reducers.ts
index 3a31f00..5c0b3cd 100644
--- a/src/reducers.ts
+++ b/src/reducers.ts
@@ -9,6 +9,9 @@ import {
REGISTER_USER_REQUEST,
REGISTER_USER_FAILURE,
REGISTER_USER_SUCCESS,
+ DELETE_USER_REQUEST,
+ DELETE_USER_FAILURE,
+ DELETE_USER_SUCCESS,
} from './actions';
import type { UserType } from './types/data';
@@ -17,11 +20,13 @@ interface RootState {
isLoggingIn: boolean;
isFetchingUserData: boolean;
isRegisteringUser: boolean;
+ isDeletingUser: boolean;
userToken: string | null;
user: UserType | null;
loginError: Record | null;
userError: Record | null;
registerError: Record | null;
+ deleteUserError: Record | null;
}
const initialState: RootState = {
@@ -29,11 +34,13 @@ const initialState: RootState = {
isLoggingIn: false,
isFetchingUserData: false,
isRegisteringUser: false,
+ isDeletingUser: false,
userToken: null,
user: null,
loginError: null,
userError: null,
registerError: null,
+ deleteUserError: null,
};
// FIXME: refactor using redux slices
@@ -79,6 +86,16 @@ export default function appReducers(state = initialState, action: any) {
return { ...state, isRegisteringUser: false, isAuthenticated: true, user: userData, userToken: token };
+ /* Delete user */
+ case DELETE_USER_REQUEST:
+ return { ...state, isDeletingUser: true, deleteUserError: null };
+
+ case DELETE_USER_FAILURE:
+ return { ...state, isDeletingUser: false, deleteUserError: action.deleteUserError };
+
+ case DELETE_USER_SUCCESS:
+ return initialState;
+
default:
return state;
}
diff --git a/src/types/data.ts b/src/types/data.ts
index 2de790a..7f8381c 100644
--- a/src/types/data.ts
+++ b/src/types/data.ts
@@ -30,4 +30,5 @@ export interface UserType {
last_membership: MembershipType | null;
is_volunteer: boolean;
is_member: boolean;
+ username: string | null;
}
diff --git a/src/types/navigation.ts b/src/types/navigation.ts
index 08c0ec4..30aab5a 100644
--- a/src/types/navigation.ts
+++ b/src/types/navigation.ts
@@ -14,6 +14,7 @@ export type UserStackParamList = {
Membership: undefined;
Login: undefined;
UserRegister: undefined;
+ UserDelete: undefined;
};
export type HomeTabParamList = {