diff --git a/.env b/.env
new file mode 100644
index 0000000..54b749c
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+EXPO_PUBLIC_API_URL: "http://127.0.0.1:8000/api"
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 05647d5..fdb373c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,3 +33,11 @@ yarn-error.*
# typescript
*.tsbuildinfo
+
+# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
+# The following patterns were generated by expo-cli
+
+expo-env.d.ts
+# @end expo-cli
+
+.gz
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..dcdb142
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,23 @@
+{
+ "arrowParens": "always",
+ "bracketSpacing": true,
+ "endOfLine": "lf",
+ "htmlWhitespaceSensitivity": "css",
+ "insertPragma": false,
+ "singleAttributePerLine": false,
+ "bracketSameLine": false,
+ "jsxBracketSameLine": false,
+ "jsxSingleQuote": false,
+ "printWidth": 80,
+ "proseWrap": "preserve",
+ "quoteProps": "as-needed",
+ "requirePragma": false,
+ "semi": true,
+ "singleQuote": false,
+ "tabWidth": 2,
+ "trailingComma": "es5",
+ "useTabs": true,
+ "embeddedLanguageFormatting": "auto",
+ "vueIndentScriptAndStyle": false,
+ "parser": "typescript"
+}
\ No newline at end of file
diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz
index 58027fd..7155dbd 100644
Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ
diff --git a/app/(for-not-verified)/_layout.tsx b/app/(for-not-verified)/_layout.tsx
index 7bb4249..8f6edf0 100644
--- a/app/(for-not-verified)/_layout.tsx
+++ b/app/(for-not-verified)/_layout.tsx
@@ -5,9 +5,9 @@ import { Redirect, Slot } from "expo-router";
* Use it on protected screens
*/
export default function ProtectedLayout() {
- const [access] = useAuth((state) => [state.access]);
+ const [access] = useAuth((state) => [state.access]);
- if (access) return ;
+ if (access) return ;
- return ;
+ return ;
}
diff --git a/app/(for-not-verified)/login.tsx b/app/(for-not-verified)/login.tsx
index 32e892f..706964d 100644
--- a/app/(for-not-verified)/login.tsx
+++ b/app/(for-not-verified)/login.tsx
@@ -1,10 +1,10 @@
import {
- ActivityIndicator,
- StyleSheet,
- TouchableOpacity,
- View,
- Text,
+ ActivityIndicator,
+ StyleSheet,
+ TouchableOpacity,
+ View,
} from "react-native";
+import { Text, useTheme } from "react-native-paper";
import { router } from "expo-router";
import { useForm } from "react-hook-form";
import ControlledInput from "../../components/ControlledInput";
@@ -13,80 +13,90 @@ import { CredentialsData } from "../../stores/auth/types";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import CenteredLayout from "../../components/CenteredLayout/CenteredLayout";
+import { Button } from "react-native-paper";
const defaultValues = { username: "", password: "" };
const loginSchema = z.object({
- username: z.string().min(1, "Pole jest wymagane"),
- password: z.string().min(1, "Pole jest wymagane"),
+ username: z.string().min(1, "Pole jest wymagane"),
+ password: z.string().min(1, "Pole jest wymagane"),
});
export default function TabOneScreen() {
- const { control, handleSubmit, setError } = useForm({
- defaultValues,
- resolver: zodResolver(loginSchema),
- });
- const [login, loading] = useAuth((state) => [state.login, state.loading]);
- const onSubmit = async (credentials: CredentialsData) => {
- try {
- await login(credentials);
- } catch (err) {
- console.error(err);
- }
- };
+ const theme = useTheme();
+ const { control, handleSubmit, setError } = useForm({
+ defaultValues,
+ resolver: zodResolver(loginSchema),
+ });
+ const [login, loading] = useAuth((state) => [state.login, state.loading]);
+ const onSubmit = async (credentials: CredentialsData) => {
+ try {
+ await login(credentials);
+ router.replace("/home");
+ } catch (err) {
+ console.error(err);
+ }
+ };
- return (
-
-
-
-
- router.push("/register")}>
-
- Don't have an account?
-
- {" Sign up"}
-
-
-
-
- Enter
-
- {loading ? : null}
-
-
- );
+ return (
+
+
+
+
+
+ {loading ? : null}
+ router.push("/register")}>
+
+ Nie posiadasz konta?
+
+
+ {"Zarejestruj się"}
+
+
+
+
+ );
}
const styles = StyleSheet.create({
- button: {
- backgroundColor: "#15CA78",
- color: "#fff",
- paddingHorizontal: 12,
- paddingVertical: 8,
- borderRadius: 16,
- elevation: 4,
- // boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.15)"
- },
- buttonText: {
- color: "#fff",
- },
- separator: {
- marginVertical: 30,
- height: 1,
- width: "80%",
- },
+ button: {
+ backgroundColor: "#15CA78",
+ color: "#fff",
+ paddingHorizontal: 12,
+ paddingVertical: 8,
+ borderRadius: 16,
+ elevation: 4,
+ // boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.15)"
+ },
+ buttonText: {
+ color: "#fff",
+ },
+ separator: {
+ marginVertical: 30,
+ height: 1,
+ width: "80%",
+ },
});
diff --git a/app/(for-not-verified)/register.tsx b/app/(for-not-verified)/register.tsx
index 23a4699..7c66660 100644
--- a/app/(for-not-verified)/register.tsx
+++ b/app/(for-not-verified)/register.tsx
@@ -1,9 +1,9 @@
import {
- ActivityIndicator,
- StyleSheet,
- TouchableOpacity,
- View,
- Text,
+ ActivityIndicator,
+ StyleSheet,
+ TouchableOpacity,
+ View,
+ ScrollView,
} from "react-native";
import { router } from "expo-router";
@@ -13,96 +13,149 @@ import { useAuth } from "../../stores/auth/auth";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import CenteredLayout from "../../components/CenteredLayout/CenteredLayout";
+import { Button, Text, useTheme } from "react-native-paper";
-const defaultValues = { username: "", password: "", rePassword: "" };
+const defaultValues = {
+ username: "",
+ password: "",
+ rePassword: "",
+ phone_number: "",
+ email: "",
+ first_name: "",
+ last_name: "",
+};
const registerSchema = z
- .object({
- username: z.string().min(1, "Pole jest wymagane"),
- password: z.string().min(1, "Pole jest wymagane"),
- rePassword: z.string().min(1, "Pole jest wymagane"),
- })
- .refine(({ password, rePassword }) => password === rePassword, {
- path: ["password"],
- message: "Passwords don't match",
- });
+ .object({
+ username: z.string().min(1, "Pole jest wymagane"),
+ password: z.string().min(1, "Pole jest wymagane"),
+ rePassword: z.string().min(1, "Pole jest wymagane"),
+ phone_number: z.string().min(1, "Pole jest wymagane"),
+ email: z.string().min(1, "Pole jest wymagane"),
+ first_name: z.string().min(1, "Pole jest wymagane"),
+ last_name: z.string().min(1, "Pole jest wymagane"),
+ })
+ .refine(({ password, rePassword }) => password === rePassword, {
+ path: ["password"],
+ message: "Passwords don't match",
+ });
export default function TabOneScreen() {
- const { control, handleSubmit } = useForm({
- defaultValues,
- resolver: zodResolver(registerSchema),
- });
- const [register, loading] = useAuth((state) => [
- state.register,
- state.loading,
- ]);
+ const theme = useTheme();
+ const { control, handleSubmit } = useForm({
+ defaultValues,
+ resolver: zodResolver(registerSchema),
+ });
+ const [register, loading] = useAuth((state) => [
+ state.register,
+ state.loading,
+ ]);
- const onSubmit = async (credentials: typeof defaultValues) => {
- try {
- await register(credentials);
- router.replace("/edit-user");
- } catch (err) {
- console.error(JSON.stringify(err));
- }
- };
+ const onSubmit = async (credentials: typeof defaultValues) => {
+ const { rePassword, ...rest } = credentials;
+ try {
+ await register(rest);
+ router.replace("/home");
+ } catch (err) {
+ console.error(JSON.stringify(err));
+ }
+ };
- return (
-
-
-
-
-
- router.push("/login")}
- >
-
- I have an account!
-
- {" Sign in"}
-
-
-
-
- Done!
-
- {loading ? : null}
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {loading ? : null}
+ router.push("/login")}>
+
+ Posiadasz konto?
+
+
+ {"Zaloguj się"}
+
+
+
+
+
+ );
}
const styles = StyleSheet.create({
- button: {
- backgroundColor: "#15CA78",
- color: "#fff",
- paddingHorizontal: 12,
- paddingVertical: 8,
- borderRadius: 16,
- elevation: 4,
- // boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.15)"
- },
- buttonText: {
- color: "#fff",
- },
+ button: {
+ backgroundColor: "#15CA78",
+ color: "#fff",
+ paddingHorizontal: 12,
+ paddingVertical: 8,
+ borderRadius: 16,
+ elevation: 4,
+ // boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.15)"
+ },
+ buttonText: {
+ color: "#fff",
+ },
});
diff --git a/app/(protected)/_layout.tsx b/app/(protected)/_layout.tsx
index 2994b4a..7c02bc6 100644
--- a/app/(protected)/_layout.tsx
+++ b/app/(protected)/_layout.tsx
@@ -7,21 +7,28 @@ import { StyleSheet, View } from "react-native";
* Use it on protected screens
*/
export default function ProtectedLayout() {
- const [access] = useAuth((state) => [state.access]);
+ const [access] = useAuth((state) => [state.access]);
- if (!access) return ;
+ if (!access) return ;
- return (
-
-
-
- );
+ return (
+
+
+
+ );
}
const styles = StyleSheet.create({
- container: {
- flex: 1,
- alignItems: "center",
- justifyContent: "center",
- },
+ container: {
+ flex: 1,
+ alignItems: "center",
+ justifyContent: "center",
+ },
});
diff --git a/app/(protected)/creator/creator.tsx b/app/(protected)/creator/creator.tsx
new file mode 100644
index 0000000..5d0f70d
--- /dev/null
+++ b/app/(protected)/creator/creator.tsx
@@ -0,0 +1,116 @@
+import ControlledInput from "@/components/ControlledInput";
+import { ScrollView, View, StyleSheet } from "react-native";
+import { z } from "zod";
+import { Text, IconButton } from "react-native-paper";
+import { useForm } from "react-hook-form";
+import { zodResolver } from "@hookform/resolvers/zod";
+// import { DatePickerInput } from "react-native-paper-dates";
+
+const defaultValues = {
+ title: "",
+ description: "",
+ short_description: "",
+ start_timestamp: 0,
+ end_timestamp: 0,
+ location: "Kraków",
+ price: 0,
+};
+const registerSchema = z.object({
+ title: z.string().min(1, "Pole jest wymagane"),
+ description: z.string().min(1, "Pole jest wymagane"),
+ short_description: z.string().min(1, "Pole jest wymagane"),
+ start_timestamp: z.number().min(1, "Pole jest wymagane"),
+ end_timestamp: z.number().min(1, "Pole jest wymagane"),
+ location: z.string().min(1, "Pole jest wymagane"),
+ price: z.number().min(1, "Pole jest wymagane"),
+});
+export default function eventCreator() {
+ const returnPress = () => {
+ console.log("Powrót");
+ };
+ const { control, handleSubmit } = useForm({
+ defaultValues,
+ resolver: zodResolver(registerSchema),
+ });
+ return (
+
+
+
+ Mój Profil
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+const styles = StyleSheet.create({
+ title: {
+ textAlign: "right",
+ },
+ myButton: {
+ display: "flex",
+ },
+ titleView: {
+ padding: 20,
+ },
+ mainView: { flex: 1 },
+ button: {
+ backgroundColor: "#15CA78",
+ color: "#fff",
+ paddingHorizontal: 12,
+ paddingVertical: 8,
+ borderRadius: 16,
+ elevation: 4,
+ // boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.15)"
+ },
+});
diff --git a/app/(protected)/creator/myButton.tsx b/app/(protected)/creator/myButton.tsx
new file mode 100644
index 0000000..1e50e5c
--- /dev/null
+++ b/app/(protected)/creator/myButton.tsx
@@ -0,0 +1,43 @@
+import { router } from "expo-router";
+import { View, StyleSheet } from "react-native";
+import { IconButton, Text } from "react-native-paper";
+export default function MyButton() {
+ const pressHandler = () => {
+ router.push("/creator/creator");
+ };
+ return (
+
+
+
+ Dodaj post
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ create: {
+ backgroundColor: "#004A33",
+ },
+ background: {
+ backgroundColor: "#00A271",
+ width: "100%",
+ padding: 40,
+ borderTopLeftRadius: 20,
+ borderTopRightRadius: 20,
+ marginTop: 20,
+ display: "flex",
+ justifyContent: "center",
+ flexDirection: "row",
+ alignContent: "center",
+ },
+});
diff --git a/app/(protected)/home.tsx b/app/(protected)/home.tsx
new file mode 100644
index 0000000..57d84aa
--- /dev/null
+++ b/app/(protected)/home.tsx
@@ -0,0 +1,96 @@
+import { FlatList, ScrollView, StyleSheet, View } from "react-native";
+import { IconButton, Text, useTheme } from "react-native-paper";
+import { useEffect, useState } from "react";
+import Post, { postInterface } from "./post";
+import api from "@/stores/api";
+import MyButton from "./creator/myButton";
+
+const renderItem = ({ item }: { item: postInterface }) => {
+ return (
+
+ );
+};
+
+export default function TabOneScreen() {
+ const [data, setData] = useState>([]);
+
+ useEffect(() => {
+ async function asyncCall() {
+ try {
+ const fetchedData = await api.getPosts();
+ setData(fetchedData); // Update state with the fetched data
+ } catch (err) {
+ console.error(err);
+ }
+ }
+ asyncCall();
+ }, []);
+
+ const pressHandler = () => {
+ console.log("Dzieki dziala");
+ };
+ return (
+
+
+
+ Mój Profil
+
+
+
+ item.id}
+ extraData={data}
+ />
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ title: {
+ textAlign: "right",
+ },
+ titleView: {
+ padding: 20,
+ },
+ mainView: { flex: 1 },
+ button: {
+ backgroundColor: "#15CA78",
+ color: "#fff",
+ paddingHorizontal: 12,
+ paddingVertical: 8,
+ borderRadius: 16,
+ elevation: 4,
+ // boxShadow: "0px 4px 4px 0px rgba(0, 0, 0, 0.15)"
+ },
+ buttonText: {
+ color: "#fff",
+ },
+ separator: {
+ marginVertical: 30,
+ height: 1,
+ width: "80%",
+ },
+});
diff --git a/app/(protected)/index.tsx b/app/(protected)/index.tsx
deleted file mode 100644
index 3a9de8d..0000000
--- a/app/(protected)/index.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { View } from "react-native";
-
-export default function HomePage() {
- return XD;
-}
diff --git a/app/(protected)/post.tsx b/app/(protected)/post.tsx
new file mode 100644
index 0000000..467ee9b
--- /dev/null
+++ b/app/(protected)/post.tsx
@@ -0,0 +1,38 @@
+import { Card, Text, Button } from "react-native-paper";
+
+export type postInterface = {
+ id: string;
+ title: string;
+ short_description: string;
+ description: string;
+ issuer_id: number;
+ created_at: number;
+ start_timestamp: number;
+ end_timestamp: number;
+ location: string;
+ price: number;
+ visible: boolean;
+};
+export default function Post({
+ id,
+ title,
+ short_description,
+ description,
+ issuer_id,
+ created_at,
+ start_timestamp,
+ end_timestamp,
+ location,
+ price,
+ visible,
+}: postInterface) {
+ return (
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/+html.tsx b/app/+html.tsx
index cb31090..40ee654 100644
--- a/app/+html.tsx
+++ b/app/+html.tsx
@@ -1,30 +1,33 @@
-import { ScrollViewStyleReset } from 'expo-router/html';
+import { ScrollViewStyleReset } from "expo-router/html";
// This file is web-only and used to configure the root HTML for every
// web page during static rendering.
// The contents of this function only run in Node.js environments and
// do not have access to the DOM or browser APIs.
export default function Root({ children }: { children: React.ReactNode }) {
- return (
-
-
-
-
-
+ return (
+
+
+
+
+
- {/*
+ {/*
Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
*/}
-
+
- {/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
-
- {/* Add any additional elements that you want globally available on web... */}
-
- {children}
-
- );
+ {/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
+
+ {/* Add any additional elements that you want globally available on web... */}
+
+ {children}
+
+ );
}
const responsiveBackground = `
diff --git a/app/+not-found.tsx b/app/+not-found.tsx
index b61f360..02f4858 100644
--- a/app/+not-found.tsx
+++ b/app/+not-found.tsx
@@ -1,5 +1,9 @@
import { Stack } from "expo-router";
export default function NotFoundScreen() {
- return ;
+ return (
+
+ );
}
diff --git a/app/_layout.tsx b/app/_layout.tsx
index 637656f..35187a8 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -3,49 +3,63 @@ import { useFonts } from "expo-font";
import { Stack } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import { useEffect } from "react";
+import {
+ MD3LightTheme as DefaultTheme,
+ PaperProvider,
+} from "react-native-paper";
export {
- // Catch any errors thrown by the Layout component.
- ErrorBoundary,
+ // Catch any errors thrown by the Layout component.
+ ErrorBoundary,
} from "expo-router";
export const unstable_settings = {
- // Ensure that reloading on `/modal` keeps a back button present.
- initialRouteName: "(tabs)",
+ // Ensure that reloading on `/modal` keeps a back button present.
+ initialRouteName: "(tabs)",
};
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
- const [loaded, error] = useFonts({
- SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
- ...FontAwesome.font,
- });
-
- // Expo Router uses Error Boundaries to catch errors in the navigation tree.
- useEffect(() => {
- if (error) throw error;
- }, [error]);
-
- useEffect(() => {
- if (loaded) {
- SplashScreen.hideAsync();
- }
- }, [loaded]);
-
- if (!loaded) {
- return null;
- }
-
- return ;
+ const [loaded, error] = useFonts({
+ SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
+ ...FontAwesome.font,
+ });
+
+ // Expo Router uses Error Boundaries to catch errors in the navigation tree.
+ useEffect(() => {
+ if (error) throw error;
+ }, [error]);
+
+ useEffect(() => {
+ if (loaded) {
+ SplashScreen.hideAsync();
+ }
+ }, [loaded]);
+
+ if (!loaded) {
+ return null;
+ }
+
+ return ;
}
+const theme = {
+ ...DefaultTheme,
+ colors: {
+ ...DefaultTheme.colors,
+ primary: "black",
+ secondary: "#DED4D4",
+ },
+};
+
function RootLayoutNav() {
- return (
-
-
-
-
- );
+ return (
+
+
+
+
+
+ );
}
diff --git a/assets/images/szczala.png b/assets/images/szczala.png
new file mode 100644
index 0000000..8c43057
Binary files /dev/null and b/assets/images/szczala.png differ
diff --git a/babel.config.js b/babel.config.js
index 33acf98..bf7fcf8 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -1,6 +1,11 @@
module.exports = function (api) {
- api.cache(true);
- return {
- presets: ['babel-preset-expo']
- };
+ api.cache(true);
+ return {
+ presets: ["babel-preset-expo"],
+ env: {
+ production: {
+ plugins: ["react-native-paper/babel"],
+ },
+ },
+ };
};
diff --git a/components/CenteredLayout/CenteredLayout.tsx b/components/CenteredLayout/CenteredLayout.tsx
index 74b4b86..578e2ae 100644
--- a/components/CenteredLayout/CenteredLayout.tsx
+++ b/components/CenteredLayout/CenteredLayout.tsx
@@ -1,26 +1,38 @@
-import { View, Text, StyleSheet } from "react-native";
+import { View, StyleSheet } from "react-native";
+import { Surface, Text } from "react-native-paper";
+import { useTheme } from "react-native-paper";
-export default function CenteredLayout({ children, title }: { children: React.ReactNode, title: string }) {
- return (
- {/* Separator */}
-
- {title}
- {children}
-)
+export default function CenteredLayout({
+ children,
+ title,
+}: {
+ children: React.ReactNode;
+ title: string;
+}) {
+ const theme = useTheme();
+ return (
+
+ {/* Separator */}
+
+
+
+ {title}
+
+
+ {children}
+
+ );
}
const styles = StyleSheet.create({
- container: {
- flex: 1,
- alignItems: "center",
- justifyContent: "center",
- rowGap: 16,
- padding: 48,
- },
- title: {
- fontSize: 36,
- fontWeight: "bold",
- color: "#15CA78",
- fontFamily: 'Roboto'
- }
-});
\ No newline at end of file
+ container: {
+ flex: 1,
+ alignItems: "center",
+ justifyContent: "flex-start",
+ rowGap: 16,
+ padding: 48,
+ },
+});
diff --git a/components/ControlledInput/ControlledInput.tsx b/components/ControlledInput/ControlledInput.tsx
index 58a22d0..254504b 100644
--- a/components/ControlledInput/ControlledInput.tsx
+++ b/components/ControlledInput/ControlledInput.tsx
@@ -1,39 +1,42 @@
import { FieldValues, useController } from "react-hook-form";
import { ControlledInputProps } from "./types";
import React, { ReactElement } from "react";
-import { TextInput, View, Text } from "react-native";
+import { View } from "react-native";
+import { TextInput, Text, Icon } from "react-native-paper";
const ControlledInput = ({
- name,
- label,
- control,
- secure,
- placeholder = "Type..."
-}: ControlledInputProps): ReactElement => {
- const {
- field: { value, onChange },
- fieldState: { error },
- } = useController({ control, name });
+ name,
+ label,
+ control,
+ secure,
+ iconName,
+ placeholder = "Type...",
+}: ControlledInputProps & { iconName?: string }): ReactElement => {
+ const {
+ field: { value, onChange },
+ fieldState: { error },
+ } = useController({ control, name });
- return (
-
- {label}
-
- {error?.message ? {error.message} : null}
-
- );
+ return (
+
+
+ {label}
+
+ : null
+ }
+ mode="outlined"
+ placeholder={placeholder}
+ secureTextEntry={secure}
+ value={value}
+ onChangeText={onChange}
+ />
+ {error?.message ? (
+ {error.message}
+ ) : null}
+
+ );
};
export default ControlledInput;
diff --git a/components/ControlledInput/types.ts b/components/ControlledInput/types.ts
index bde6692..c79baf4 100644
--- a/components/ControlledInput/types.ts
+++ b/components/ControlledInput/types.ts
@@ -1,9 +1,9 @@
import { Control, FieldValues, Path } from "react-hook-form";
export type ControlledInputProps = {
- name: Path;
- label: string;
- control: Control;
- secure?: boolean;
- placeholder?: string;
+ name: Path;
+ label: string;
+ control: Control;
+ secure?: boolean;
+ placeholder?: string;
};
diff --git a/package.json b/package.json
index 41fd127..aaf5290 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,8 @@
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
- "test": "jest --watchAll"
+ "test": "jest --watchAll",
+ "prettier": "npx prettier . --write"
},
"jest": {
"preset": "jest-expo"
@@ -30,7 +31,8 @@
"react-dom": "18.2.0",
"react-hook-form": "^7.51.0",
"react-native": "0.73.5",
- "react-native-safe-area-context": "4.8.2",
+ "react-native-paper": "^5.12.3",
+ "react-native-safe-area-context": "^4.9.0",
"react-native-screens": "~3.29.0",
"react-native-web": "~0.19.6",
"zod": "^3.22.4",
@@ -41,6 +43,7 @@
"@types/react": "~18.2.45",
"jest": "^29.2.1",
"jest-expo": "~50.0.4",
+ "prettier": "^3.2.5",
"react-test-renderer": "18.2.0",
"typescript": "^5.1.3"
},
diff --git a/stores/api/api.ts b/stores/api/api.ts
index c94003a..2ae997a 100644
--- a/stores/api/api.ts
+++ b/stores/api/api.ts
@@ -2,93 +2,100 @@ import { AxiosHeaders, AxiosResponse } from "axios";
import { client } from "./client";
import { CredentialsData, TokensData, UserData } from "../auth/types";
import AsyncStorage from "@react-native-async-storage/async-storage";
+import { postInterface } from "@/app/(protected)/post";
class API {
- async login(payload: CredentialsData): Promise {
- const { data } = await this.request({
- url: "/auth/jwt/create/",
- method: "POST",
- payload,
- });
+ async login(payload: CredentialsData): Promise {
+ const { data } = await this.request({
+ url: "/auth/jwt/create/",
+ method: "POST",
+ payload,
+ });
- return data;
- }
+ return data;
+ }
- async register(payload: CredentialsData): Promise {
- await this.request(
- {
- url: "/auth/users/",
- method: "POST",
- payload,
- },
- true
- );
- }
+ async register(payload: CredentialsData): Promise {
+ await this.request(
+ {
+ url: "/auth/users/",
+ method: "POST",
+ payload,
+ },
+ true
+ );
+ }
- async refreshToken(refresh: string): Promise<{ access: string }> {
- const { data } = await this.request({
- url: "/auth/jwt/refresh/",
- method: "POST",
- payload: { refresh },
- });
+ async refreshToken(refresh: string): Promise<{ access: string }> {
+ const { data } = await this.request({
+ url: "/auth/jwt/refresh/",
+ method: "POST",
+ payload: { refresh },
+ });
- return data;
- }
+ return data;
+ }
- async verifyToken(token: string): Promise {
- await this.request({
- url: "/auth/jwt/verify/",
- method: "POST",
- payload: { token },
- });
- }
+ async verifyToken(token: string): Promise {
+ await this.request({
+ url: "/auth/jwt/verify/",
+ method: "POST",
+ payload: { token },
+ });
+ }
- async editUser(payload: UserData): Promise {
- await this.request({
- payload,
- method: "PATCH",
- url: "/auth/users/me/", // temporarly
- });
- }
+ async editUser(payload: UserData): Promise {
+ await this.request({
+ payload,
+ method: "PATCH",
+ url: "/auth/users/me/", // temporarly
+ });
+ }
- async getUser(): Promise {
- const { data } = await this.request({
- url: "/auth/users/me/",
- method: "GET",
- });
- return data;
- }
+ async getUser(): Promise {
+ const { data } = await this.request({
+ url: "/auth/users/me/",
+ method: "GET",
+ });
+ return data;
+ }
+ async getPosts(): Promise> {
+ const { data } = await this.request>({
+ url: "/posts/",
+ method: "GET",
+ });
+ return data;
+ }
- async request(
- {
- url,
- method,
- headers,
- payload,
- }: {
- url: string;
- method: "GET" | "POST" | "PATCH";
- headers?: AxiosHeaders;
- payload?: any;
- },
- disableToken?: boolean
- ): Promise> {
- const accessToken = await AsyncStorage.getItem("access");
-
- return client.request({
- url,
- method,
- headers: {
- ...(accessToken && !disableToken
- ? {
- Authorization: `Bearer ${accessToken}`,
- }
- : {}),
- ...headers,
- },
- data: payload,
- });
- }
+ async request(
+ {
+ url,
+ method,
+ headers,
+ payload,
+ }: {
+ url: string;
+ method: "GET" | "POST" | "PATCH";
+ headers?: AxiosHeaders;
+ payload?: any;
+ },
+ disableToken?: boolean
+ ): Promise> {
+ const accessToken = await AsyncStorage.getItem("access");
+ return client.request({
+ url,
+ method,
+ headers: {
+ ...(accessToken && !disableToken
+ ? {
+ Authorization: `Bearer ${accessToken}`,
+ }
+ : {}),
+ ...headers,
+ },
+ data: payload,
+ });
+ }
}
export default new API();
diff --git a/stores/api/client.ts b/stores/api/client.ts
index 303ef8b..2590b41 100644
--- a/stores/api/client.ts
+++ b/stores/api/client.ts
@@ -1,7 +1,7 @@
import axios from "axios";
export const client = axios.create({
- baseURL: process.env.EXPO_PUBLIC_API_URL,
- timeout: 5000,
- proxy: false,
+ baseURL: process.env.EXPO_PUBLIC_API_URL,
+ timeout: 5000,
+ proxy: false,
});
diff --git a/stores/auth/auth.ts b/stores/auth/auth.ts
index d2e6853..3905db9 100644
--- a/stores/auth/auth.ts
+++ b/stores/auth/auth.ts
@@ -6,112 +6,112 @@ import { verifyAccessToken } from "./utils";
import { router } from "expo-router";
export const useAuth = create((set) => ({
- access: null,
- refresh: null,
- username: null,
- loading: false,
- checkedAccessInStorage: false,
- restoreTokensLoading: false,
- user: null,
+ access: null,
+ refresh: null,
+ username: null,
+ loading: false,
+ checkedAccessInStorage: false,
+ restoreTokensLoading: false,
+ user: null,
- login: async (credentials: CredentialsData) => {
- set({ loading: true });
- try {
- const tokens = await API.login({
- username: credentials.username,
- password: credentials.password,
- });
- AsyncStorage.setItem("access", tokens.access);
- AsyncStorage.setItem("refresh", tokens.refresh);
- const userData = await API.getUser();
- set({
- ...tokens,
- user: userData,
- });
- router.replace("/");
- } finally {
- set({ loading: false });
- }
- },
+ login: async (credentials: CredentialsData) => {
+ set({ loading: true });
+ try {
+ const tokens = await API.login({
+ username: credentials.username,
+ password: credentials.password,
+ });
+ AsyncStorage.setItem("access", tokens.access);
+ AsyncStorage.setItem("refresh", tokens.refresh);
+ const userData = await API.getUser();
+ set({
+ ...tokens,
+ user: userData,
+ });
+ router.replace("/home");
+ } finally {
+ set({ loading: false });
+ }
+ },
- editUser: async (payload: UserData) => {
- set({ user: payload });
- API.editUser(payload);
- },
+ editUser: async (payload: UserData) => {
+ set({ user: payload });
+ API.editUser(payload);
+ },
- register: async (credentials: CredentialsData) => {
- set({ loading: true });
- try {
- await API.register({
- username: credentials.username,
- password: credentials.password,
- });
- const tokens = await API.login({
- username: credentials.username,
- password: credentials.password,
- });
- AsyncStorage.setItem("access", tokens.access);
- AsyncStorage.setItem("refresh", tokens.refresh);
- const userData = await API.getUser();
- set({
- access: tokens.access,
- refresh: tokens.refresh,
- restoreTokensLoading: false,
- user: userData,
- });
- router.replace("/");
- } finally {
- set({ loading: false });
- }
- },
+ register: async (credentials: CredentialsData) => {
+ set({ loading: true });
+ try {
+ await API.register({
+ username: credentials.username,
+ password: credentials.password,
+ });
+ const tokens = await API.login({
+ username: credentials.username,
+ password: credentials.password,
+ });
+ AsyncStorage.setItem("access", tokens.access);
+ AsyncStorage.setItem("refresh", tokens.refresh);
+ const userData = await API.getUser();
+ set({
+ access: tokens.access,
+ refresh: tokens.refresh,
+ restoreTokensLoading: false,
+ user: userData,
+ });
+ router.replace("/home");
+ } finally {
+ set({ loading: false });
+ }
+ },
- refreshToken: async (refresh: string) => {
- set({ loading: true });
- try {
- const { access } = await API.refreshToken(refresh);
- AsyncStorage.setItem("access", access);
- set({ access });
- } catch {
- set({ access: null, refresh: null });
- } finally {
- set({ loading: false });
- }
- },
+ refreshToken: async (refresh: string) => {
+ set({ loading: true });
+ try {
+ const { access } = await API.refreshToken(refresh);
+ AsyncStorage.setItem("access", access);
+ set({ access });
+ } catch {
+ set({ access: null, refresh: null });
+ } finally {
+ set({ loading: false });
+ }
+ },
- restoreTokens: async () => {
- set({ restoreTokensLoading: true });
- const access = await AsyncStorage.getItem("access");
- const refresh = await AsyncStorage.getItem("refresh");
+ restoreTokens: async () => {
+ set({ restoreTokensLoading: true });
+ const access = await AsyncStorage.getItem("access");
+ const refresh = await AsyncStorage.getItem("refresh");
- if (!refresh) {
- set({ restoreTokensLoading: false });
- return;
- }
+ if (!refresh) {
+ set({ restoreTokensLoading: false });
+ return;
+ }
- const verifiedAccess = await verifyAccessToken(access);
- if (verifiedAccess) {
- const userData = await API.getUser();
- set({
- access: verifiedAccess,
- refresh,
- restoreTokensLoading: false,
- user: userData,
- });
- return;
- }
+ const verifiedAccess = await verifyAccessToken(access);
+ if (verifiedAccess) {
+ const userData = await API.getUser();
+ set({
+ access: verifiedAccess,
+ refresh,
+ restoreTokensLoading: false,
+ user: userData,
+ });
+ return;
+ }
- try {
- const { access } = await API.refreshToken(refresh);
- AsyncStorage.setItem("access", access);
- const userData = await API.getUser();
- set({
- access,
- refresh,
- restoreTokensLoading: false,
- user: userData,
- });
- } catch {
- set({ restoreTokensLoading: false });
- }
- },
+ try {
+ const { access } = await API.refreshToken(refresh);
+ AsyncStorage.setItem("access", access);
+ const userData = await API.getUser();
+ set({
+ access,
+ refresh,
+ restoreTokensLoading: false,
+ user: userData,
+ });
+ } catch {
+ set({ restoreTokensLoading: false });
+ }
+ },
}));
diff --git a/stores/auth/types.ts b/stores/auth/types.ts
index 172c663..8aedead 100644
--- a/stores/auth/types.ts
+++ b/stores/auth/types.ts
@@ -1,32 +1,32 @@
export type TokensData = {
- access: string;
- refresh: string;
+ access: string;
+ refresh: string;
};
export type AuthStore = {
- access: string | null;
- refresh: string | null;
- username: string | null;
- loading: boolean;
- user: UserData | null;
- restoreTokensLoading: boolean;
- login: (credentials: CredentialsData) => Promise;
- register: (credentials: CredentialsData) => Promise;
- refreshToken: (token: string) => Promise;
- restoreTokens: () => Promise;
- editUser: (payload: UserData) => Promise;
+ access: string | null;
+ refresh: string | null;
+ username: string | null;
+ loading: boolean;
+ user: UserData | null;
+ restoreTokensLoading: boolean;
+ login: (credentials: CredentialsData) => Promise;
+ register: (credentials: CredentialsData) => Promise;
+ refreshToken: (token: string) => Promise;
+ restoreTokens: () => Promise;
+ editUser: (payload: UserData) => Promise;
};
export type CredentialsData = {
- username: string;
- password: string;
+ username: string;
+ password: string;
};
export type UserData = {
- id: number;
- email: string;
+ id: number;
+ email: string;
};
export type RegisterData = CredentialsData & {
- re_password: string;
+ re_password: string;
};
diff --git a/stores/auth/utils.ts b/stores/auth/utils.ts
index ef2ae23..e1f9c29 100644
--- a/stores/auth/utils.ts
+++ b/stores/auth/utils.ts
@@ -1,12 +1,12 @@
import API from "../api";
export const verifyAccessToken = async (
- access?: string | null
+ access?: string | null
): Promise => {
- if (!access) return;
+ if (!access) return;
- try {
- await API.verifyToken(access);
- return access;
- } catch {}
+ try {
+ await API.verifyToken(access);
+ return access;
+ } catch {}
};
diff --git a/yarn.lock b/yarn.lock
index bb94222..5414afd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1715,6 +1715,18 @@ __metadata:
languageName: node
linkType: hard
+"@callstack/react-theme-provider@npm:^3.0.9":
+ version: 3.0.9
+ resolution: "@callstack/react-theme-provider@npm:3.0.9"
+ dependencies:
+ deepmerge: "npm:^3.2.0"
+ hoist-non-react-statics: "npm:^3.3.0"
+ peerDependencies:
+ react: ">=16.3.0"
+ checksum: 10c0/ac3463383c35e1a4ef813e869532bf86d3e83a4c211b00616c832a5f08545f04f07f769726664b5010124575af2cf8152aabfb7d4c37a64b22ae8a7f9490df0e
+ languageName: node
+ linkType: hard
+
"@expo/bunyan@npm:^4.0.0":
version: 4.0.0
resolution: "@expo/bunyan@npm:4.0.0"
@@ -4485,7 +4497,7 @@ __metadata:
languageName: node
linkType: hard
-"color-convert@npm:^1.9.0":
+"color-convert@npm:^1.9.0, color-convert@npm:^1.9.3":
version: 1.9.3
resolution: "color-convert@npm:1.9.3"
dependencies:
@@ -4517,7 +4529,7 @@ __metadata:
languageName: node
linkType: hard
-"color-string@npm:^1.9.0":
+"color-string@npm:^1.6.0, color-string@npm:^1.9.0":
version: 1.9.1
resolution: "color-string@npm:1.9.1"
dependencies:
@@ -4527,6 +4539,16 @@ __metadata:
languageName: node
linkType: hard
+"color@npm:^3.1.2":
+ version: 3.2.1
+ resolution: "color@npm:3.2.1"
+ dependencies:
+ color-convert: "npm:^1.9.3"
+ color-string: "npm:^1.6.0"
+ checksum: 10c0/39345d55825884c32a88b95127d417a2c24681d8b57069413596d9fcbb721459ef9d9ec24ce3e65527b5373ce171b73e38dbcd9c830a52a6487e7f37bf00e83c
+ languageName: node
+ linkType: hard
+
"color@npm:^4.2.3":
version: 4.2.3
resolution: "color@npm:4.2.3"
@@ -4915,6 +4937,13 @@ __metadata:
languageName: node
linkType: hard
+"deepmerge@npm:^3.2.0":
+ version: 3.3.0
+ resolution: "deepmerge@npm:3.3.0"
+ checksum: 10c0/143bc6b6cd8a1216565c61c0fe38bf43fe691fb6876fb3f5727c6e323defe4e947c68fbab9957e17e837c5594a56af885c5834d23dc6cf2c41bef97090005104
+ languageName: node
+ linkType: hard
+
"deepmerge@npm:^4.2.2, deepmerge@npm:^4.3.0":
version: 4.3.1
resolution: "deepmerge@npm:4.3.1"
@@ -6210,6 +6239,15 @@ __metadata:
languageName: node
linkType: hard
+"hoist-non-react-statics@npm:^3.3.0":
+ version: 3.3.2
+ resolution: "hoist-non-react-statics@npm:3.3.2"
+ dependencies:
+ react-is: "npm:^16.7.0"
+ checksum: 10c0/fe0889169e845d738b59b64badf5e55fa3cf20454f9203d1eb088df322d49d4318df774828e789898dcb280e8a5521bb59b3203385662ca5e9218a6ca5820e74
+ languageName: node
+ linkType: hard
+
"hosted-git-info@npm:^3.0.2":
version: 3.0.8
resolution: "hosted-git-info@npm:3.0.8"
@@ -8992,11 +9030,13 @@ __metadata:
expo-web-browser: "npm:~12.8.2"
jest: "npm:^29.2.1"
jest-expo: "npm:~50.0.4"
+ prettier: "npm:^3.2.5"
react: "npm:18.2.0"
react-dom: "npm:18.2.0"
react-hook-form: "npm:^7.51.0"
react-native: "npm:0.73.5"
- react-native-safe-area-context: "npm:4.8.2"
+ react-native-paper: "npm:^5.12.3"
+ react-native-safe-area-context: "npm:^4.9.0"
react-native-screens: "npm:~3.29.0"
react-native-web: "npm:~0.19.6"
react-test-renderer: "npm:18.2.0"
@@ -9109,6 +9149,15 @@ __metadata:
languageName: node
linkType: hard
+"prettier@npm:^3.2.5":
+ version: 3.2.5
+ resolution: "prettier@npm:3.2.5"
+ bin:
+ prettier: bin/prettier.cjs
+ checksum: 10c0/ea327f37a7d46f2324a34ad35292af2ad4c4c3c3355da07313339d7e554320f66f65f91e856add8530157a733c6c4a897dc41b577056be5c24c40f739f5ee8c6
+ languageName: node
+ linkType: hard
+
"pretty-bytes@npm:5.6.0":
version: 5.6.0
resolution: "pretty-bytes@npm:5.6.0"
@@ -9416,7 +9465,7 @@ __metadata:
languageName: node
linkType: hard
-"react-is@npm:^16.13.0, react-is@npm:^16.13.1":
+"react-is@npm:^16.13.0, react-is@npm:^16.13.1, react-is@npm:^16.7.0":
version: 16.13.1
resolution: "react-is@npm:16.13.1"
checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1
@@ -9430,13 +9479,29 @@ __metadata:
languageName: node
linkType: hard
-"react-native-safe-area-context@npm:4.8.2":
- version: 4.8.2
- resolution: "react-native-safe-area-context@npm:4.8.2"
+"react-native-paper@npm:^5.12.3":
+ version: 5.12.3
+ resolution: "react-native-paper@npm:5.12.3"
+ dependencies:
+ "@callstack/react-theme-provider": "npm:^3.0.9"
+ color: "npm:^3.1.2"
+ use-latest-callback: "npm:^0.1.5"
+ peerDependencies:
+ react: "*"
+ react-native: "*"
+ react-native-safe-area-context: "*"
+ react-native-vector-icons: "*"
+ checksum: 10c0/0adc7c5dd3e47af357b9e0b700e9663d32d9e6e47cba10b26af76a4a63197bda47e5295d6bdc031904039aaa12b875a135fa512c323ea44d4c1ae97d68e1d356
+ languageName: node
+ linkType: hard
+
+"react-native-safe-area-context@npm:^4.9.0":
+ version: 4.9.0
+ resolution: "react-native-safe-area-context@npm:4.9.0"
peerDependencies:
react: "*"
react-native: "*"
- checksum: 10c0/5430ef5d4f3510debd964423aa7ae2f9f4f3aea6e928b0dc6f7e63c21e967f3e71377a3b5df0bd5ceca291c4818670ee77afb3fc7a1091061449ae0fd3ed00b2
+ checksum: 10c0/27bb6b759d4d36f39e4a4a2d7e4d65f2e4e95175fc9ffeac63249680da54fd4cd0a4da064314d9ce579182200327967447da17cf8ea31badbaa4087de3302f42
languageName: node
linkType: hard
@@ -11173,7 +11238,7 @@ __metadata:
languageName: node
linkType: hard
-"use-latest-callback@npm:^0.1.9":
+"use-latest-callback@npm:^0.1.5, use-latest-callback@npm:^0.1.9":
version: 0.1.9
resolution: "use-latest-callback@npm:0.1.9"
peerDependencies: