Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve UI #2

Merged
merged 4 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/api/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const useGetPosts = (type: string | null) => {
fetch(getUrl(type!))
.then((res) => res.json())
.then((data) => data.posts),
select: (data) => data.reverse(),
staleTime: 1000 * 60 * 5,
});
};
Expand Down
42 changes: 35 additions & 7 deletions src/app/(app)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,56 @@
import { useGetPosts } from "@api/hooks";
import { isRouteAuthenticated } from "@auth/routes";
import LoadingSpinner from "@components/LoadingSpinner";
import { PostCard } from "@components/PostCard";
import { Text, makeStyles } from "@rneui/themed";
import { usePostStore } from "@stores/postStore";
import { useUserStore } from "@stores/userStore";
import { usePathname } from "expo-router";
import { StatusBar } from "expo-status-bar";
import { ScrollView } from "react-native";
import { Redirect, usePathname } from "expo-router";
import { ScrollView, View } from "react-native";

import Login from "./login";
const useStyles = makeStyles((theme) => ({
container: {
display: "flex",
justifyContent: "center",
alignItems: "center",
marginTop: 20,
},
text: {
color: theme.colors.white,
},
loadingSpinner: {
marginTop: 20,
},
}));

const App = () => {
const styles = useStyles();
const { user } = useUserStore();
const route = usePathname();
const postsType = usePostStore((state) => state.type);
const { data } = useGetPosts(postsType);

if (!user && isRouteAuthenticated(route)) {
return <Login />;
return <Redirect href="/login" />;
}

return (
<ScrollView>
<StatusBar style="auto" />
{data?.map((post) => <PostCard key={post.url} post={post} />)}
{postsType &&
data &&
data.map((post) => <PostCard key={post.url} post={post} />)}

{postsType && !data && (
<View style={styles.loadingSpinner}>
<LoadingSpinner size="large" />
</View>
)}

{!postsType && (
<View style={styles.container}>
<Text style={styles.text}>Please select a type!</Text>
</View>
)}
</ScrollView>
);
};
Expand Down
18 changes: 8 additions & 10 deletions src/app/(app)/login.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { useLoginUser } from "@auth/hooks";
import ErrorScreen from "@components/ErrorScreen";
import LoadingSpinner from "@components/LoadingSpinner";
import LoginField from "@components/LoginField";
import { Redirect } from "expo-router";
import { useState } from "react";
Expand All @@ -14,13 +12,11 @@ const Login = () => {
return <Redirect href="/" />;
}

if (loading) {
return <LoadingSpinner />;
}

if (error) {
return <ErrorScreen error={error.message} />;
}
const isDisabled =
!email ||
!password ||
!/^[^@]+@[^@]+\.[^@]+$/g.test(email) ||
password.length < 5;

return (
<LoginField
Expand All @@ -29,8 +25,10 @@ const Login = () => {
onEmailChange={setEmail}
password={password}
onPasswordChange={setPassword}
disabled={!email || !password}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!(email && password)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok e vaka ne treba da raboti kopceto ako barem edno fali

disabled={isDisabled}
onButtonClick={() => login(email, password)}
isLoading={loading ?? false}
error={error}
/>
);
};
Expand Down
12 changes: 12 additions & 0 deletions src/app/(app)/logout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useLogoutUser } from "@auth/hooks";
import { Redirect } from "expo-router";

const Logout = () => {
const { logout } = useLogoutUser();

logout();

return <Redirect href="/" />;
};

export default Logout;
18 changes: 8 additions & 10 deletions src/app/(app)/register.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { useRegisterUser } from "@auth/hooks";
import ErrorScreen from "@components/ErrorScreen";
import LoadingSpinner from "@components/LoadingSpinner";
import LoginField from "@components/LoginField";
import { Redirect } from "expo-router";
import { useState } from "react";
Expand All @@ -14,13 +12,11 @@ const Register = () => {
return <Redirect href="/" />;
}

if (loading) {
return <LoadingSpinner />;
}

if (error) {
return <ErrorScreen error={error.message} />;
}
const isDisabled =
!email ||
!password ||
!/^[^@]+@[^@]+\.[^@]+$/g.test(email) ||
password.length < 5;

return (
<LoginField
Expand All @@ -29,8 +25,10 @@ const Register = () => {
onEmailChange={setEmail}
password={password}
onPasswordChange={setPassword}
disabled={!email || !password}
disabled={isDisabled}
onButtonClick={() => register(email, password)}
isLoading={loading ?? false}
error={error}
/>
);
};
Expand Down
7 changes: 7 additions & 0 deletions src/auth/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { queryClient } from "@api/queryClient";
import { firebaseApp } from "@auth/firebase";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { usePostStore } from "@stores/postStore";
import { useUserStore } from "@stores/userStore";
import {
createUserWithEmailAndPassword,
Expand Down Expand Up @@ -64,6 +66,7 @@ export const useLogoutUser = () => {
const { setUser } = useUserStore();
const [loading, setLoading] = useState<boolean | null>(null);
const [error, setError] = useState<Error | null>(null);
const setType = usePostStore((state) => state.setType);

const logout = useCallback(() => {
setLoading(true);
Expand All @@ -72,7 +75,11 @@ export const useLogoutUser = () => {
.signOut()
.then(() => {
setUser(null);
setType(null);
setLoading(false);
queryClient.invalidateQueries({
predicate: (query) => query.queryKey[0] === "posts",
});
})
.catch((error) => {
setError(error);
Expand Down
73 changes: 57 additions & 16 deletions src/components/AppHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,91 @@
import { Header, Text, makeStyles } from "@rneui/themed";
import { useLogoutUser } from "@auth/hooks";
import { Button, Chip, Header, Text, makeStyles } from "@rneui/themed";
import { usePostStore } from "@stores/postStore";
import { useUserStore } from "@stores/userStore";
import React from "react";
import { ScrollView, TouchableOpacity } from "react-native";
import { ScrollView } from "react-native";

const useStyles = makeStyles((theme) => ({
headerContainer: {
backgroundColor: theme.colors.primary,
justifyContent: "space-around",
height: 100,
},
scrollView: {
flexGrow: 0,
},
option: {
paddingHorizontal: 10,
},
optionText: {
color: theme.colors.white,
},
loginText: {
color: theme.colors.white,
},
chip: {
marginHorizontal: 5,
},
selectedChip: {
borderStyle: "solid",
borderWidth: 1,
borderColor: theme.colors.white,
},
}));

const AppHeader = () => {
const styles = useStyles();
const { setType, types } = usePostStore((state) => state);
const {
setType,
types: postTypes,
type: selectedType,
} = usePostStore((state) => state);
const user = useUserStore((state) => state.user);
const { logout, loading } = useLogoutUser();

const handlePostTypeSelect = (type: string) => {
setType(type);
};

return (
<Header
leftComponent={
user ? (
<Button
icon={{
name: "logout",
type: "material",
color: "white",
}}
onPress={() => {
logout();
}}
loading={Boolean(loading)}
type="solid"
/>
) : undefined
}
centerComponent={
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={styles.scrollView}
alwaysBounceHorizontal
>
{types.map((type, index) => (
<TouchableOpacity
key={index}
onPress={() => handlePostTypeSelect(type)}
style={styles.option}
>
<Text style={styles.optionText}>{type.toUpperCase()}</Text>
</TouchableOpacity>
))}
{user ? (
postTypes.map((postType) => (
<Chip
key={postType}
containerStyle={[
styles.chip,
selectedType === postType && styles.selectedChip,
]}
title={postType.toUpperCase()}
type={selectedType === postType ? "outline" : "solid"}
titleStyle={styles.optionText}
onPress={() => handlePostTypeSelect(postType)}
size="md"
/>
))
) : (
<Text style={styles.loginText}>Please login to see posts!</Text>
)}
</ScrollView>
}
containerStyle={styles.headerContainer}
Expand Down
8 changes: 7 additions & 1 deletion src/components/ErrorScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ const useStyles = makeStyles((theme) => ({
margin: "auto",
color: theme.colors.error,
},
message: {
color: theme.colors.white,
marginBottom: theme.spacing.xl,
},
}));

type Props = {
Expand All @@ -24,7 +28,9 @@ const ErrorScreen = ({ error }: Props) => {

return (
<View style={styles.container}>
<Text h3>The application has crashed.</Text>
<Text h4 style={styles.message}>
The application has crashed :'(
</Text>
<Text style={styles.errorText}>{error}</Text>
</View>
);
Expand Down
Loading