aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--App.js75
-rw-r--r--api.js31
-rw-r--r--components/Edit.jsx60
-rw-r--r--components/List.jsx71
-rw-r--r--components/Login.jsx19
-rw-r--r--components/Main.jsx26
-rw-r--r--components/Menu.jsx100
-rw-r--r--components/RemoveNoteButton.jsx31
-rw-r--r--components/index.js3
-rw-r--r--helpers.jsx99
10 files changed, 276 insertions, 239 deletions
diff --git a/App.js b/App.js
index 336ffee..2d40b0e 100644
--- a/App.js
+++ b/App.js
@@ -1,31 +1,13 @@
-import { StatusBar } from 'expo-status-bar';
-import { StyleSheet, SafeAreaView, Text } from 'react-native';
-import { useState, useEffect } from 'react';
-import AsyncStorage from '@react-native-async-storage/async-storage';
-import { Login, List, Edit } from './components'
+import { StatusBar } from 'expo-status-bar'
+import { StyleSheet, SafeAreaView, Text } from 'react-native'
+import { useState, useEffect } from 'react'
+import AsyncStorage from '@react-native-async-storage/async-storage'
+import Main from './components/Main'
+import Login from './components/Login'
export default function App() {
- const [session, setSession] = useState();
- const [error, setError] = useState(null);
- const [edit, setEdit] = useState(null)
-
- const login = async (e, p) => {
- try {
- const response = await fetch('https://apps.pruss.it/api/login', {
- method: 'POST',
- headers: { 'Content-Type': 'plain/text; charset=utf-8' },
- body: JSON.stringify({ email: e, password: p })
- })
- const cookies = response.headers?.map?.['set-cookie']
- const data = await response.json()
- if (data?.isLoggedIn) {
- await AsyncStorage.setItem('session', JSON.stringify({...data, cookies}))
- setSession({ ...data, cookies })
- }
- } catch(e) {
- showError('Error while logging in')
- }
- }
+ const [session, setSession] = useState()
+ const [error, setError] = useState(null)
const showError = (e) => {
setError(e)
@@ -34,48 +16,29 @@ export default function App() {
useEffect(() => {
AsyncStorage.getItem('session')
- .then(s => setSession(JSON.parse(s)))
+ .then(session => setSession(JSON.parse(session)))
.catch(() => setSession(null))
- }, []);
+ }, [])
- if (error) return (
+ if (error || session === undefined) return (
<SafeAreaView style={styles.container}>
- <Text style={styles.error}>{error}</Text>
+ {error
+ ? <Text style={styles.error}>{error}</Text>
+ : <Text>Loading...</Text>}
</SafeAreaView>
)
- if (session === undefined) return (
- <SafeAreaView style={styles.container}>
- <Text>Loading...</Text>
- </SafeAreaView>
- );
-
return (
<SafeAreaView style={styles.container}>
{
session === null
- ? <Login login={login} />
- : edit
- ? (
- <Edit
- edit={edit}
- setEdit={setEdit}
- session={session}
- setSession={setSession}
- showError={showError}
- />
- ) : (
- <List
- session={session}
- showError={showError}
- setEdit={setEdit}
- />
- )
+ ? <Login setSession={setSession} showError={showError} />
+ : <Main session={session} setSession={setSession} showError={showError} />
}
<StatusBar style="auto" />
</SafeAreaView>
- );
-};
+ )
+}
const styles = StyleSheet.create({
container: {
@@ -85,4 +48,4 @@ const styles = StyleSheet.create({
error: {
color: 'red',
}
-});
+})
diff --git a/api.js b/api.js
new file mode 100644
index 0000000..3441967
--- /dev/null
+++ b/api.js
@@ -0,0 +1,31 @@
+const API = 'https://apps.pruss.it/api'
+
+export const login = ({ email, password }) => fetch(`${API}/login`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'plain/text; charset=utf-8' },
+ body: JSON.stringify({ email, password })
+})
+
+export const getList = ({ session }) => fetch(`${API}/notes`, {
+ 'Cookie': session.cookies
+})
+
+export const getNote = ({ note, session }) => fetch(`${API}/notes/${note.noteId}`, {
+ method: 'GET', headers: { 'Cookie': session.cookies },
+})
+
+export const createNote = ({ title, content, session }) => fetch(`${API}/notes`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'plain/text; charset=utf-8', 'Cookie': session.cookies },
+ body: JSON.stringify({ title, content })
+})
+
+export const editNote = ({ note, title, content, session }) => fetch(`${API}/notes/${note._id}`, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'plain/text; charset=utf-8', 'Cookie': session.cookies },
+ body: JSON.stringify({ title, noteId: note.noteId, content })
+})
+
+export const removeNote = ({ note, session }) => fetch(`${API}/notes/${note._id}`, {
+ method: 'DELETE', headers: { 'Cookie': session.cookies },
+})
diff --git a/components/Edit.jsx b/components/Edit.jsx
index 3ca7b32..7818637 100644
--- a/components/Edit.jsx
+++ b/components/Edit.jsx
@@ -1,62 +1,20 @@
import { StyleSheet, Text, TextInput , View } from 'react-native';
import { useState, useEffect } from 'react'
+import { handleGetNote, handleCreateNote, handleEditNote } from '../helpers';
import Menu from './Menu'
-const Edit = ({ edit, setEdit, session, setSession, showError }) => {
+const Edit = ({ edit: note, setEdit, session, setSession, showError }) => {
const [saving, setSaving] = useState()
- const [title, setTitle] = useState(edit ? edit.title : '')
+ const [title, setTitle] = useState(note ? note.title : '')
const [content, setContent] = useState()
- const fetchNote = async () => {
- try {
- const response = await fetch(`https://apps.pruss.it/api/notes/${edit.noteId}`, {
- method: 'GET', headers: { 'Cookie': session.cookies },
- })
- const { content } = await response.json()
- setContent(content)
- } catch(e) {
- showError('Error while fetching note')
- setEdit(null)
- }
- }
-
- const saveNote = async () => {
- try {
- setSaving(true)
- await fetch(`https://apps.pruss.it/api/notes/${edit._id}`, {
- method: 'PUT',
- headers: { 'Content-Type': 'plain/text; charset=utf-8', 'Cookie': session.cookies },
- body: JSON.stringify({ title, noteId: edit.noteId, content })
- })
- setSaving(false)
- setEdit(null)
- } catch(e) {
- showError('Error while saving note')
- setSaving(false)
- setEdit(null)
- }
- }
-
- createNote = async () => {
- try {
- setSaving(true)
- await fetch(`https://apps.pruss.it/api/notes`, {
- method: 'POST',
- headers: { 'Content-Type': 'plain/text; charset=utf-8', 'Cookie': session.cookies },
- body: JSON.stringify({ title, content })
- })
- setSaving(false)
- setEdit(null)
- } catch(e) {
- showError('Error while saving note')
- setSaving(false)
- setEdit(null)
- }
- }
+ const saveNote = () => note._id
+ ? handleEditNote({ note, title, content, setSaving, setEdit, session, showError })
+ : handleCreateNote({ title, content, setSaving, setEdit, session, showError })
useEffect(() => {
- if (edit?._id) {
- fetchNote()
+ if (note?._id) {
+ handleGetNote({ note, setContent, setEdit, session, showError })
} else {
setContent('')
}
@@ -69,7 +27,7 @@ const Edit = ({ edit, setEdit, session, setSession, showError }) => {
setSession={setSession}
showError={showError}
setEdit={setEdit}
- saveNote={edit._id ? saveNote : createNote}
+ saveNote={saveNote}
/>
<View style={styles.container}>
<TextInput
diff --git a/components/List.jsx b/components/List.jsx
index b7bdc07..b280d4a 100644
--- a/components/List.jsx
+++ b/components/List.jsx
@@ -1,8 +1,11 @@
-import { StyleSheet, Text, View, Pressable, Alert } from 'react-native'
+import { StyleSheet, Text } from 'react-native'
import SwipeableFlatList from 'react-native-swipeable-list'
import { useState, useEffect } from 'react'
+import { getList } from '../api'
import Note from './Note'
import Menu from './Menu'
+import RemoveNoteButton from './RemoveNoteButton'
+import { handleRemove } from "../helpers";
const List = ({ session, setSession, showError, setEdit }) => {
const [list, setList] = useState()
@@ -11,7 +14,7 @@ const List = ({ session, setSession, showError, setEdit }) => {
const fetchNotes = async () => {
setLoading(true)
try {
- const response = await fetch('https://apps.pruss.it/api/notes', { 'Cookie': session.cookies } )
+ const response = await getList({ session })
const data = await response.json()
setList(data)
} catch(e) {
@@ -25,51 +28,6 @@ const List = ({ session, setSession, showError, setEdit }) => {
fetchNotes()
}, [])
- const deleteNote = async (note) => {
- setLoading(true)
- try {
- await fetch(`https://apps.pruss.it/api/notes/${note._id}`, {
- method: 'DELETE', headers: { 'Cookie': session.cookies },
- })
- fetchNotes()
- } catch(e) {
- showError('Error while removing note')
- } finally {
- setLoading(false)
- }
- }
-
- const deleteItem = note => {
- Alert.alert(
- 'Are you sure?',
- `Note "${note.title}" will be permanently removed`,
- [
- {
- text: 'Remove',
- onPress: () => deleteNote(note),
- style: 'destructive',
- },
- {
- text: 'Cancel',
- onPress: () => {},
- style: 'cancel',
- },
- ],
- );
- };
-
- const removeBtn = (note) => {
- return (
- <View style={styles.buttonsContainer}>
- <View style={styles.button}>
- <Pressable onPress={() => deleteItem(note)}>
- <Text style={styles.buttonText}>Delete</Text>
- </Pressable>
- </View>
- </View>
- );
- };
-
return (
<>
<Menu
@@ -90,8 +48,10 @@ const List = ({ session, setSession, showError, setEdit }) => {
onRefresh={fetchNotes}
refreshing={loading}
maxSwipeDistance={80}
- renderQuickActions={({item}) => removeBtn(item)}
bounceFirstRowOnMount={false}
+ renderQuickActions={({item}) => RemoveNoteButton({
+ removeNote: () => handleRemove({ note: item, session, fetchNotes, setLoading, showError })
+ })}
/>
)
}
@@ -104,21 +64,6 @@ const styles = StyleSheet.create({
color: 'white',
padding: 20,
},
- button: {
- width: 80,
- alignItems: 'center',
- justifyContent: 'center',
- backgroundColor: 'red',
- },
- buttonText: {
- fontWeight: 'bold',
- color: 'white',
- },
- buttonsContainer: {
- flex: 1,
- flexDirection: 'row',
- justifyContent: 'flex-end',
- },
});
export default List;
diff --git a/components/Login.jsx b/components/Login.jsx
index 4c6ffb0..8b42913 100644
--- a/components/Login.jsx
+++ b/components/Login.jsx
@@ -1,9 +1,10 @@
-import { StyleSheet, Text, TextInput, Pressable, View } from 'react-native';
-import { useState } from 'react';
+import { StyleSheet, Text, TextInput, Pressable, View } from 'react-native'
+import { useState } from 'react'
+import { handleLogin } from '../helpers'
-const Login = ({ login }) => {
+const Login = ({ setSession, showError }) => {
const [email, setEmail] = useState('');
- const [pass, setPass] = useState('');
+ const [password, setPassword] = useState('');
const disabled = (e, p) => !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e) || p.length < 6;
return (
@@ -31,13 +32,13 @@ const Login = ({ login }) => {
autoComplete="password-new"
secureTextEntry={true}
textContentType="newPassword"
- value={pass}
- onChange={e => setPass(e.nativeEvent.text)}
+ value={password}
+ onChange={e => setPassword(e.nativeEvent.text)}
/>
<Pressable
- onPress={() => login(email, pass)}
- style={{...styles.button, opacity: disabled(email, pass) ? .3 : 1}}
- disabled={disabled(email, pass)}
+ onPress={() => handleLogin({ email, password, setSession, showError })}
+ style={{...styles.button, opacity: disabled(email, password) ? .3 : 1}}
+ disabled={disabled(email, password)}
>
<Text style={styles.buttonText}>Login</Text>
</Pressable>
diff --git a/components/Main.jsx b/components/Main.jsx
new file mode 100644
index 0000000..3f48c3e
--- /dev/null
+++ b/components/Main.jsx
@@ -0,0 +1,26 @@
+import { List, Edit } from '.'
+import { useState } from 'react'
+
+const Main = ({ session, setSession, showError }) => {
+ const [edit, setEdit] = useState(null)
+
+ return edit
+ ? (
+ <Edit
+ edit={edit}
+ setEdit={setEdit}
+ session={session}
+ setSession={setSession}
+ showError={showError}
+ />
+ ) : (
+ <List
+ session={session}
+ setSession={setSession}
+ showError={showError}
+ setEdit={setEdit}
+ />
+ )
+}
+
+export default Main
diff --git a/components/Menu.jsx b/components/Menu.jsx
index fb82f34..519fe94 100644
--- a/components/Menu.jsx
+++ b/components/Menu.jsx
@@ -1,61 +1,49 @@
-import { StyleSheet, Text, View, Alert } from 'react-native';
-import AsyncStorage from '@react-native-async-storage/async-storage';
-import { confirmLogout } from '../helpers'
+import { StyleSheet, Text, View } from 'react-native';
+import { handleLogout } from '../helpers'
-const Menu = ({ session, setSession, setEdit, showError, saveNote }) => {
- const logout = async () => {
- try {
- await AsyncStorage.clear();
- setSession(null)
- } catch(e) {
- showError('Error while logging out')
+const Menu = ({ session, setSession, setEdit, showError, saveNote }) => (
+ <View style={styles.menu}>
+ {
+ saveNote
+ ? (
+ <>
+ <Text
+ style={styles.menuText}
+ onPress={() => setEdit(null)}
+ >
+ Back
+ </Text>
+ <Text
+ style={styles.menuText}
+ onPress={saveNote}
+ >
+ Save
+ </Text>
+ </>
+ ) : (
+ <>
+ <Text
+ style={styles.menuText}
+ onPress={() => setEdit({})}
+ >
+ New Note
+ </Text>
+ <Text
+ style={styles.menuText}
+ >
+ Sort
+ </Text>
+ <Text
+ style={styles.menuText}
+ onPress={() => handleLogout({ session, setSession, showError })}
+ >
+ {session.email}
+ </Text>
+ </>
+ )
}
- }
-
- return (
- <View style={styles.menu}>
- {
- saveNote
- ? (
- <>
- <Text
- style={styles.menuText}
- onPress={() => setEdit(null)}
- >
- Back
- </Text>
- <Text
- style={styles.menuText}
- onPress={saveNote}
- >
- Save
- </Text>
- </>
- ) : (
- <>
- <Text
- style={styles.menuText}
- onPress={() => setEdit({})}
- >
- New Note
- </Text>
- <Text
- style={styles.menuText}
- >
- Sort
- </Text>
- <Text
- style={styles.menuText}
- onPress={() => confirmLogout({ logout, email: session.email })}
- >
- {session.email}
- </Text>
- </>
- )
- }
- </View>
- )
-}
+ </View>
+)
const styles = StyleSheet.create({
menu: {
diff --git a/components/RemoveNoteButton.jsx b/components/RemoveNoteButton.jsx
new file mode 100644
index 0000000..d88d6b0
--- /dev/null
+++ b/components/RemoveNoteButton.jsx
@@ -0,0 +1,31 @@
+import { StyleSheet, Text, View, Pressable } from 'react-native'
+
+const RemoveNoteButton = ({ removeNote }) => (
+ <View style={styles.buttonsContainer}>
+ <View style={styles.button}>
+ <Pressable onPress={removeNote}>
+ <Text style={styles.buttonText}>Delete</Text>
+ </Pressable>
+ </View>
+ </View>
+);
+
+const styles = StyleSheet.create({
+ button: {
+ width: 80,
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: 'red',
+ },
+ buttonText: {
+ fontWeight: 'bold',
+ color: 'white',
+ },
+ buttonsContainer: {
+ flex: 1,
+ flexDirection: 'row',
+ justifyContent: 'flex-end',
+ },
+});
+
+export default RemoveNoteButton;
diff --git a/components/index.js b/components/index.js
index 0f227df..7323846 100644
--- a/components/index.js
+++ b/components/index.js
@@ -1,7 +1,6 @@
import Edit from './Edit'
import List from './List'
-import Login from './Login'
import Menu from './Menu'
import Note from './Note'
-export { Edit, List, Login, Menu, Note }
+export { Edit, List, Menu, Note }
diff --git a/helpers.jsx b/helpers.jsx
index cf95ac2..427158d 100644
--- a/helpers.jsx
+++ b/helpers.jsx
@@ -1,9 +1,34 @@
+import AsyncStorage from '@react-native-async-storage/async-storage'
import { Alert } from 'react-native';
+import { login, getNote, editNote, createNote, removeNote } from './api'
+
+export const handleLogin = async ({ email, password, setSession, showError }) => {
+ try {
+ const response = await login({ email, password })
+ const cookies = response.headers?.map?.['set-cookie']
+ const data = await response.json()
+ if (data?.isLoggedIn) {
+ await AsyncStorage.setItem('session', JSON.stringify({ ...data, cookies }))
+ setSession({ ...data, cookies })
+ }
+ } catch(e) {
+ showError('Error while logging in')
+ }
+}
+
+export const handleLogout = ({ session, setSession, showError }) => {
+ const logout = async () => {
+ try {
+ await AsyncStorage.clear();
+ setSession(null)
+ } catch(e) {
+ showError('Error while logging out')
+ }
+ }
-export const confirmLogout = ({ logout, email }) => {
Alert.alert(
'Are you sure?',
- `Do you want to log out user ${email}?`,
+ `Do you want to log out user ${session.email}?`,
[
{
text: 'Logout',
@@ -18,3 +43,73 @@ export const confirmLogout = ({ logout, email }) => {
],
);
}
+
+export const handleGetNote = async ({ note, setContent, setEdit, session, showError }) => {
+ try {
+ const response = await getNote({ note, session })
+ const { content } = await response.json()
+ setContent(content)
+ } catch(e) {
+ showError('Error while fetching note')
+ setEdit(null)
+ }
+}
+
+export const handleEditNote = async ({ note, title, content, setSaving, setEdit, session, showError }) => {
+ try {
+ setSaving(true)
+ await editNote({ note, title, content, session })
+ setSaving(false)
+ setEdit(null)
+ } catch(e) {
+ showError('Error while saving note')
+ setSaving(false)
+ setEdit(null)
+ }
+}
+
+export const handleCreateNote = async ({ title, content, setSaving, setEdit, session, showError }) => {
+ try {
+ setSaving(true)
+ await createNote({ title, content, session })
+ setSaving(false)
+ setEdit(null)
+ } catch(e) {
+ showError('Error while saving note')
+ setSaving(false)
+ setEdit(null)
+ }
+}
+
+export const handleRemove = ({ note, session, fetchNotes, setLoading, showError }) => {
+ const deleteNote = async () => {
+ setLoading(true)
+ try {
+ await removeNote({ note, session })
+ fetchNotes()
+ } catch(e) {
+ console.log(e)
+ showError('Error while removing note')
+ setLoading(false)
+ }
+ }
+
+ Alert.alert(
+ 'Are you sure?',
+ `Note "${note.title}" will be permanently removed`,
+ [
+ {
+ text: 'Remove',
+ onPress: deleteNote,
+ style: 'destructive',
+ },
+ {
+ text: 'Cancel',
+ onPress: () => {},
+ style: 'cancel',
+ },
+ ],
+ );
+};
+
+