Skip to content

Commit

Permalink
Merge pull request #114 from eurofurence/refactor/form-fixes
Browse files Browse the repository at this point in the history
Refactor/form fixes
  • Loading branch information
Requinard authored Aug 22, 2022
2 parents 4ef40e3 + 841b4bd commit c362ac1
Show file tree
Hide file tree
Showing 19 changed files with 468 additions and 284 deletions.
3 changes: 2 additions & 1 deletion app.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"backgroundColor": "#035451"
},
"updates": {
"fallbackToCacheTimeout": 0
"fallbackToCacheTimeout": 0,
"url": "https://u.expo.dev/a60a3199-98db-4eec-8c66-cda6c424377d"
},
"assetBundlePatterns": [
"assets/**/*",
Expand Down
4 changes: 3 additions & 1 deletion eas.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
"distribution": "internal"
},
"preview": {
"distribution": "internal"
"distribution": "internal",
"channel": "preview"
},
"production": {
"channel": "production",
"android": {
"buildType": "app-bundle",
"autoIncrement": "versionCode"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "ef-app_react-native",
"version": "1.0.0",
"main": "node_modules/expo/AppEntry.js",
"homepage": "http://eurofurence.github.io/ef-app_react-native/",
"homepage": "https://eurofurence.github.io/ef-app_react-native/",
"contributors": [
{
"name": "requinard"
Expand Down
119 changes: 4 additions & 115 deletions src/app/Events/FeedbackScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,138 +1,27 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { useCallback, useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { StyleSheet, TextInput } from "react-native";
import { ScrollView } from "react-native-gesture-handler";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import StarRating from "react-native-star-rating-widget";
import { z } from "zod";

import { Label } from "../../components/Atoms/Label";
import { Button } from "../../components/Containers/Button";
import { Col } from "../../components/Containers/Col";
import { Floater } from "../../components/Containers/Floater";
import { Header } from "../../components/Containers/Header";
import { useTheme } from "../../context/Theme";
import { useAppNavigation, useAppRoute } from "../../hooks/useAppNavigation";
import { FeedbackForm } from "../../components/Forms";
import { useAppRoute } from "../../hooks/useAppNavigation";
import { useAppSelector } from "../../store";
import { eventsSelector } from "../../store/eurofurence.selectors";
import { useSubmitEventFeedbackMutation } from "../../store/eurofurence.service";

const feedbackForm = z.object({
rating: z.preprocess((a) => parseInt(z.string().parse(a), 10), z.number().min(1).max(5)),
message: z.string().optional(),
});

type FeedbackForm = z.infer<typeof feedbackForm>;

export const FeedbackScreen = () => {
const theme = useTheme();
const navigation = useAppNavigation("EventFeedback");
const [submitFeedback, feedbackResult] = useSubmitEventFeedbackMutation();
const { t } = useTranslation("EventFeedback");
const { control, handleSubmit } = useForm<FeedbackForm>({
resolver: zodResolver(feedbackForm),
defaultValues: {
rating: undefined,
message: undefined,
},
});

const safe = useSafeAreaInsets();
const { params } = useAppRoute("EventFeedback");
const event = useAppSelector((state) => eventsSelector.selectById(state, params.id));

const submit = useCallback((data: FeedbackForm) => {
submitFeedback({
...data,
eventId: event!.Id,
});
}, []);

useEffect(() => {
if (feedbackResult.isSuccess) {
navigation.goBack();
}
}, [feedbackResult]);

return (
<ScrollView style={safe} stickyHeaderIndices={[0]}>
<Header>{t("header", { eventTitle: event?.Title })}</Header>
<Header>{t("header", { eventTitle: event?.Title, interpolation: { escapeValue: false } })}</Header>
<Floater containerStyle={{ marginTop: 10 }}>
<Label variant={"narrow"}>{t("explanation", { eventTitle: event?.Title })}</Label>

<Controller
control={control}
name={"rating"}
rules={{
required: true,
}}
render={({ field, fieldState }) => (
<Col type={"stretch"}>
<Label variant={"bold"} mt={16}>
{t("rating_title")}
</Label>
<StarRating
rating={field.value}
onChange={field.onChange}
minRating={1}
enableHalfStar={false}
color={theme.secondary}
style={styles.star}
starSize={52}
/>
{fieldState.error && <Label style={styles.error}>{fieldState.error.message}</Label>}
</Col>
)}
/>
<Controller
control={control}
name={"message"}
rules={{
required: false,
}}
render={({ field }) => (
<>
<Label variant={"bold"} mt={16}>
{t("message_title")}
</Label>
<TextInput {...field} style={styles.input} onChangeText={field.onChange} placeholder={t("message_placeholder")} numberOfLines={8} multiline />
</>
)}
/>

<Button onPress={handleSubmit(submit)} disabled={feedbackResult.isLoading}>
{t("submit")}
</Button>

{feedbackResult.isError && (
<Label style={styles.error} mt={16}>
{t("submit_failed")}
</Label>
)}
{feedbackResult.isLoading && <Label mt={16}>{t("submit_in_progress")}</Label>}
<FeedbackForm />
</Floater>
</ScrollView>
);
};

const styles = StyleSheet.create({
input: {
width: "100%",
borderBottomColor: "black",
borderBottomWidth: 1,
paddingVertical: 8,
marginBottom: 16,
},
star: {
marginTop: 16,
marginBottom: 8,
marginLeft: "auto",
marginRight: "auto",
},
error: {
fontSize: 10,
color: "#a01010",
},
});
167 changes: 3 additions & 164 deletions src/app/MainMenu/PagerLogin.tsx
Original file line number Diff line number Diff line change
@@ -1,168 +1,7 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { FC, useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { StyleSheet, View, ViewStyle } from "react-native";
import { TextInput } from "react-native-gesture-handler";
import { z } from "zod";
import { FC } from "react";
import { StyleSheet, View } from "react-native";

import { Label } from "../../components/Atoms/Label";
import { Button } from "../../components/Containers/Button";
import { Row } from "../../components/Containers/Row";
import { useTheme } from "../../context/Theme";
import { useSentryProfiler } from "../../sentryHelpers";
import { usePostTokenMutation } from "../../store/authorization.service";

const loginSchema = z.object({
regno: z.preprocess((a) => parseInt(z.string().parse(a), 10), z.number().positive()),
username: z.string().min(1),
password: z.string().min(1),
});

type LoginSchema = z.infer<typeof loginSchema>;

export type LoginFormProps = {
style?: ViewStyle;
close?: () => void;
};

export const LoginForm: FC<LoginFormProps> = ({ style, close }) => {
const { t } = useTranslation("Settings", { keyPrefix: "login" });
const theme = useTheme();
useSentryProfiler("LoginForm");

const {
control,
handleSubmit,
formState: { errors },
} = useForm<LoginSchema>({
resolver: zodResolver(loginSchema),
});
const [login, result] = usePostTokenMutation();

const onSubmit = (data: LoginSchema) => {
login({
// TODO: Fix types here.
RegNo: data.regno,
Username: data.username,
Password: data.password,
});
};

useEffect(() => {
if (result.isSuccess && close) {
close();
}
}, [result, close]);

return (
<View style={style}>
<Label type="caption">{t("enter_username")}</Label>
{errors.username?.message && (
<Label type="minor" color="warning">
{errors.username?.message}
</Label>
)}
<Controller
control={control}
name={"username"}
rules={{
required: true,
}}
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
style={[styles.marginAfter, styles.input]}
placeholder={t("hint_username")}
placeholderTextColor={theme.soften}
onChangeText={onChange}
onBlur={onBlur}
value={value}
autoCapitalize={"none"}
/>
)}
/>

<Label type="caption">{t("enter_reg")}</Label>
{errors.regno?.message && (
<Label type="minor" color="warning">
{errors.regno?.message}
</Label>
)}

<Controller
control={control}
name={"regno"}
rules={{
required: true,
}}
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
style={[styles.marginAfter, styles.input]}
placeholder={t("hint_reg")}
placeholderTextColor={theme.soften}
onChangeText={onChange}
onBlur={onBlur}
value={value?.toString()}
autoComplete={"username"}
autoCapitalize={"none"}
textContentType={"username"}
keyboardType={"numeric"}
/>
)}
/>
<Label type="caption">{t("enter_password")}</Label>
{errors.password?.message && (
<Label type="minor" color="warning">
{errors.password?.message}
</Label>
)}

<Controller
control={control}
name={"password"}
rules={{
required: true,
}}
render={({ field: { onChange, onBlur, value, ...field } }) => (
<TextInput
{...field}
style={[styles.marginAfter, styles.input]}
selectTextOnFocus
placeholder={t("hint_password")}
placeholderTextColor={theme.soften}
onChangeText={onChange}
onBlur={onBlur}
value={value}
autoComplete={"password"}
secureTextEntry
autoCapitalize={"none"}
textContentType={"password"}
contextMenuHidden={false}
/>
)}
/>
{result.error && (
<Label type="minor" color="warning">
{t("login_error")}
</Label>
)}
{result.isLoading && <Label>{t("logging_in")}</Label>}
<Row style={styles.marginBefore}>
{close && (
<Button style={styles.rowLeft} outline icon="chevron-left" onPress={close}>
{t("back_button")}
</Button>
)}
<Button style={styles.rowRight} outline={false} icon="login" onPress={handleSubmit(onSubmit)}>
{t("login_button")}
</Button>
</Row>
<Label mt={15} variant="narrow">
{t("login_hint")}
</Label>
</View>
);
};
import { LoginForm } from "../../components/Forms";

export const PagerLogin: FC<{ close: () => void }> = ({ close }) => {
return (
Expand Down
2 changes: 1 addition & 1 deletion src/app/Settings/UserSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import { Label } from "../../components/Atoms/Label";
import { Section } from "../../components/Atoms/Section";
import { Button } from "../../components/Containers/Button";
import { Col } from "../../components/Containers/Col";
import { LoginForm } from "../../components/Forms";
import { conName } from "../../configuration";
import { useTheme } from "../../context/Theme";
import { setMomentLocale, Translations } from "../../i18n";
import { captureException } from "../../sentryHelpers";
import { useAppDispatch, useAppSelector } from "../../store";
import { logout } from "../../store/authorization.slice";
import { setAnalytics, toggleDevMenu } from "../../store/settings.slice";
import { LoginForm } from "../MainMenu/PagerLogin";
import { ThemePicker } from "./ThemePicker";

type Language = {
Expand Down
Loading

0 comments on commit c362ac1

Please sign in to comment.