removed todo_app
This commit is contained in:
parent
1eee5aa334
commit
9e8c79c046
25 changed files with 0 additions and 21516 deletions
29
todo_app/.gitignore
vendored
29
todo_app/.gitignore
vendored
|
@ -1,29 +0,0 @@
|
||||||
node_modules/
|
|
||||||
.expo/
|
|
||||||
.idea/
|
|
||||||
dist/
|
|
||||||
npm-debug.*
|
|
||||||
*.jks
|
|
||||||
*.p8
|
|
||||||
*.p12
|
|
||||||
*.key
|
|
||||||
*.mobileprovision
|
|
||||||
*.orig.*
|
|
||||||
web-build/
|
|
||||||
|
|
||||||
# macOS
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
|
|
||||||
# The following patterns were generated by expo-cli
|
|
||||||
|
|
||||||
expo-env.d.ts
|
|
||||||
|
|
||||||
|
|
||||||
api/index_.js
|
|
||||||
.env
|
|
||||||
README.md
|
|
||||||
scripts/*
|
|
||||||
hooks/*
|
|
||||||
constants/*
|
|
||||||
components/*
|
|
|
@ -1,173 +0,0 @@
|
||||||
const express = require("express");
|
|
||||||
const bodyParser = require("body-parser");
|
|
||||||
const mongoose = require("mongoose");
|
|
||||||
const crypto = require("crypto");
|
|
||||||
const User = require("./models/user");
|
|
||||||
const Todo = require("./models/todo");
|
|
||||||
const app = express();
|
|
||||||
const port = 3030;
|
|
||||||
const cors = require("cors");
|
|
||||||
const jwt = require("jsonwebtoken");
|
|
||||||
const moment = require("moment")
|
|
||||||
|
|
||||||
app.use(cors());
|
|
||||||
app.use(bodyParser.urlencoded({extended: false}));
|
|
||||||
app.use(bodyParser.json());
|
|
||||||
|
|
||||||
//connect with database
|
|
||||||
mongoose.connect(process.env.MONGO_URL).then(() => {
|
|
||||||
console.log("Connectd to mongodb");
|
|
||||||
}).catch((error) => {
|
|
||||||
console.log("Error to connect with mongodb", error);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.listen(port, () => {
|
|
||||||
console.log("Server is running on port 3030")
|
|
||||||
});
|
|
||||||
|
|
||||||
//login & register
|
|
||||||
const generateSecretKey = () => {
|
|
||||||
const secretKey = crypto.randomBytes(32).toString("hex")
|
|
||||||
return secretKey;
|
|
||||||
};
|
|
||||||
const secretKey = generateSecretKey();
|
|
||||||
|
|
||||||
app.post("/register", async(req, res) => {
|
|
||||||
try {
|
|
||||||
const {name, email, password} = req.body;
|
|
||||||
//check existing user
|
|
||||||
const existingUser = await User.findOne({email});
|
|
||||||
if(existingUser){
|
|
||||||
console.log("Email already registered");
|
|
||||||
}
|
|
||||||
|
|
||||||
const newUser = new User({name, email, password});
|
|
||||||
await newUser.save();
|
|
||||||
res.status(202).json({message: "Registration succeeded!"});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Fail to register an account!", error);
|
|
||||||
res.status(500).json({message: "Registration failed!"});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post("/login", async(req, res) => {
|
|
||||||
try {
|
|
||||||
const {email, password} = req.body;
|
|
||||||
const user = await User.findOne({email});
|
|
||||||
if(!user){
|
|
||||||
return res.status(401).json({message: "Wrong credentials: invalid username or passowrd"});
|
|
||||||
}
|
|
||||||
if(user.password !== password){
|
|
||||||
return res.status(401).json({message: "Wrong credentials: invalid username or passowrd"});
|
|
||||||
}
|
|
||||||
const token = jwt.sign({userId:user._id,}, secretKey);
|
|
||||||
res.status(200).json({token});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Fail to login!", error);
|
|
||||||
res.status(500).json({message: "Login failed!"});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//todo list
|
|
||||||
app.post("/todos/:userId", async(req, res) => {
|
|
||||||
try {
|
|
||||||
const userId = req.params.userId;
|
|
||||||
const {title, category} = req.body;
|
|
||||||
const newTodo = new Todo({
|
|
||||||
title,
|
|
||||||
category,
|
|
||||||
dueDate: moment().format("MMM Do YY")
|
|
||||||
});
|
|
||||||
await newTodo.save();
|
|
||||||
|
|
||||||
//add todo id
|
|
||||||
const user = await User.findById(userId);
|
|
||||||
if(!user){
|
|
||||||
res.status(404).json({message: "User not found!"});
|
|
||||||
}
|
|
||||||
user?.todos.push(newTodo._id);
|
|
||||||
await user.save();
|
|
||||||
|
|
||||||
res.status(200).json({message: "A list is added successfully!", todo:newTodo});
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).json({message: "Fail to add a list!"});
|
|
||||||
console.log(error)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get("/users/:userId/todos", async(req, res) => {
|
|
||||||
try {
|
|
||||||
const userId = req.params.userId;
|
|
||||||
const user = await User.findById(userId).populate("todos");
|
|
||||||
if(!user){
|
|
||||||
return res.status(404).json({message: "user not found"});
|
|
||||||
}
|
|
||||||
res.status(200).json({todos:user.todos});
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).json({message: "Error, something went wrong!"});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.patch("/todos/:todoId/complete", async(req, res) => {
|
|
||||||
try {
|
|
||||||
const todoId = req.params.todoId;
|
|
||||||
const updatedTodo = await Todo.findByIdAndUpdate(todoId, {
|
|
||||||
status:"completed"
|
|
||||||
},
|
|
||||||
{new:true}
|
|
||||||
);
|
|
||||||
if(!updatedTodo){
|
|
||||||
return res.status(404).json({error:"Todo not found"});
|
|
||||||
}
|
|
||||||
res.status(200).json({message: "Mark as completed!", todo:updatedTodo});
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).json({message: "Error, something went wrong!"});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//calendar
|
|
||||||
app.get("/users/:userId/todos/completed/:date", async(req, res) => {
|
|
||||||
try {
|
|
||||||
const date = req.params.date;
|
|
||||||
const userId = req.params.userId;
|
|
||||||
const user = await User.findById(userId);
|
|
||||||
const userToDos = await user.populate('todos');
|
|
||||||
const toDos = userToDos.todos;
|
|
||||||
|
|
||||||
const completedTodos = toDos.filter(item => {
|
|
||||||
return item.status == "completed" && // status filter
|
|
||||||
item.createdAt.getTime() >= new Date(`${date}T00:00:00.000Z`) && // gte filter
|
|
||||||
item.createdAt.getTime() <= new Date(`${date}T23:59:59.999Z`) // lt filter
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
res.status(200).json({completedTodos})
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).json({message: "Error, something went wrong!"});
|
|
||||||
console.log(error)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get("/users/:userId/todos/count", async(req, res) => {
|
|
||||||
try {
|
|
||||||
const userId = req.params.userId;
|
|
||||||
const user = await User.findById(userId);
|
|
||||||
const userToDos = await user.populate('todos');
|
|
||||||
const toDos = userToDos.todos;
|
|
||||||
const completedTodos = toDos.filter(item => {
|
|
||||||
return item.status == "completed"
|
|
||||||
});
|
|
||||||
const pendingTodos = toDos.filter(item => {
|
|
||||||
return item.status == "pending"
|
|
||||||
});
|
|
||||||
|
|
||||||
const totalCompletedTodos = completedTodos.length;
|
|
||||||
const totalPendingTodos = pendingTodos.length;
|
|
||||||
|
|
||||||
res.status(200).json({totalCompletedTodos, totalPendingTodos});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).json({message: "Error, something went wrong!"});
|
|
||||||
console.log(error)
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,28 +0,0 @@
|
||||||
const mongoose = require("mongoose");
|
|
||||||
|
|
||||||
const todoSchema = new mongoose.Schema({
|
|
||||||
title:{
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
status:{
|
|
||||||
type: String,
|
|
||||||
enum: ["pending", "completed"],
|
|
||||||
default: "pending"
|
|
||||||
},
|
|
||||||
category:{
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
dueDate:{
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
createdAt:{
|
|
||||||
type: Date,
|
|
||||||
default: Date.now
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const Todo= mongoose.model("Todo", todoSchema);
|
|
||||||
module.exports = Todo
|
|
|
@ -1,30 +0,0 @@
|
||||||
const mongoose = require("mongoose");
|
|
||||||
|
|
||||||
const userSchema = new mongoose.Schema({
|
|
||||||
name:{
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
email:{
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
unique: true,
|
|
||||||
},
|
|
||||||
password:{
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
todos:[
|
|
||||||
{
|
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
|
||||||
ref: "Todo",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
createdAt:{
|
|
||||||
type: Date,
|
|
||||||
default: Date.now
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const User = mongoose.model("User", userSchema);
|
|
||||||
module.exports = User
|
|
1388
todo_app/api/package-lock.json
generated
1388
todo_app/api/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"name": "api",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "server_side",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"start": "nodemon index.js",
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"body-parser": "^1.20.2",
|
|
||||||
"cors": "^2.8.5",
|
|
||||||
"express": "^4.19.2",
|
|
||||||
"jsonwebtoken": "^9.0.2",
|
|
||||||
"mongodb": "^6.8.0",
|
|
||||||
"mongoose": "^8.5.1",
|
|
||||||
"nodemon": "^3.1.4"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
{
|
|
||||||
"expo": {
|
|
||||||
"name": "todo_app",
|
|
||||||
"slug": "todo_app",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"orientation": "portrait",
|
|
||||||
"icon": "./assets/images/icon.png",
|
|
||||||
"scheme": "todo_app",
|
|
||||||
"userInterfaceStyle": "automatic",
|
|
||||||
"splash": {
|
|
||||||
"image": "./assets/images/splash.png",
|
|
||||||
"resizeMode": "contain",
|
|
||||||
"backgroundColor": "#ffffff"
|
|
||||||
},
|
|
||||||
"ios": {
|
|
||||||
"supportsTablet": true
|
|
||||||
},
|
|
||||||
"android": {
|
|
||||||
"adaptiveIcon": {
|
|
||||||
"foregroundImage": "./assets/images/adaptive-icon.png",
|
|
||||||
"backgroundColor": "#ffffff"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"web": {
|
|
||||||
"bundler": "metro",
|
|
||||||
"output": "static",
|
|
||||||
"favicon": "./assets/images/logo.png"
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
"expo-router"
|
|
||||||
],
|
|
||||||
"experiments": {
|
|
||||||
"typedRoutes": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
import {Stack} from "expo-router";
|
|
||||||
|
|
||||||
export default function Layout(){
|
|
||||||
return(
|
|
||||||
<Stack>
|
|
||||||
<Stack.Screen name="login" options={{headerShown: false}}/>
|
|
||||||
<Stack.Screen name="register" options={{headerShown: false}}/>
|
|
||||||
</Stack>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
import { StyleSheet, Text, View, SafeAreaView, KeyboardAvoidingView, Image, TextInput, Pressable } from 'react-native'
|
|
||||||
import React, { useEffect, useState } from 'react'
|
|
||||||
import { Fontisto } from '@expo/vector-icons';
|
|
||||||
import { Entypo } from '@expo/vector-icons';
|
|
||||||
import { useRouter } from 'expo-router';
|
|
||||||
import axios from "axios";
|
|
||||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
||||||
|
|
||||||
const login = () => {
|
|
||||||
const router = useRouter();
|
|
||||||
const [email, setEmail] = useState('');
|
|
||||||
const [password, setPassword] = useState('');
|
|
||||||
useEffect(() => {
|
|
||||||
const checkLoginStatus = async() => {
|
|
||||||
try {
|
|
||||||
const token = await AsyncStorage.getItem("authToken");
|
|
||||||
if(token){
|
|
||||||
router.replace("/(tabs)/home")
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
checkLoginStatus();
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const handleLogin = () => {
|
|
||||||
const user = {
|
|
||||||
email: email,
|
|
||||||
password: password,
|
|
||||||
};
|
|
||||||
axios.post("http://localhost:3030/login", user).then((res) => {
|
|
||||||
const token = res.data.token;
|
|
||||||
AsyncStorage.setItem("authToken", JSON.stringify(token));
|
|
||||||
router.replace("/(tabs)/home")
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SafeAreaView style={{flex:1, backgroundColor: "white", alignItems: "center", justifyContent:"center"}}>
|
|
||||||
<View>
|
|
||||||
<View style={{alignItems: "center"}}>
|
|
||||||
<Image
|
|
||||||
style={{width: 150, height: 150, resizeMode: "containe"}}
|
|
||||||
source={{
|
|
||||||
uri:"./assets/images/logo.png",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<Text style={{fontSize: 24, fontWeight: 600, color: "#222831", marginTop: 20}}>Keep Tracking</Text>
|
|
||||||
</View>
|
|
||||||
<KeyboardAvoidingView>
|
|
||||||
<View style={{alignItems: "center"}}>
|
|
||||||
<Text style={{fontSize: 16, fontWeight: 600, color: "black", marginTop: 20}}>Welcome back!</Text>
|
|
||||||
</View>
|
|
||||||
<View style={{marginTop: 50}}>
|
|
||||||
<View style={{flexDirection: "row", justifyContent: "center", alignItems: "center", gap:5, backgroundColor: "#EEEEEE", paddingHorizontal:10, borderRadius:5}}>
|
|
||||||
<Fontisto name="email" size={16} color="#31363F" />
|
|
||||||
<TextInput value={email} onChangeText={(text) => setEmail(text)} style={{color: "#31363F", width:250, outlineStyle: 'none', marginVertical: 10, fontSize:email ? 14 : 14}} placeholder='Enter your email'/>
|
|
||||||
</View>
|
|
||||||
<View style={{flexDirection: "row", justifyContent: "center", alignItems: "center", gap:5, backgroundColor: "#EEEEEE", paddingHorizontal:10, borderRadius:5, marginTop: 10}}>
|
|
||||||
<Entypo name="key" size={16} color="#31363F" />
|
|
||||||
<TextInput value={password} onChangeText={(text) => setPassword(text)} secureTextEntry={true} style={{color: "#31363F", width:250, outlineStyle: 'none', marginVertical: 10, fontSize:email ? 14 : 14}} placeholder='Enter your password'/>
|
|
||||||
</View>
|
|
||||||
<View style={{marginTop:10}}>
|
|
||||||
<Text style={{color: "#61677A", fontSize: 12 }}>Forgot password?</Text>
|
|
||||||
</View>
|
|
||||||
<View style={{marginTop: 50}}/>
|
|
||||||
<Pressable onPress={handleLogin} style={{backgroundColor: "#61677A", padding:10, borderRadius:5, alignItems: "center"}}>
|
|
||||||
<Text style={{color: "#D8D9DA", fontSize: 16, fontWeight: 600}}>Login</Text>
|
|
||||||
</Pressable>
|
|
||||||
<Pressable onPress={() => router.replace("/register")} style={{marginTop: 10}}>
|
|
||||||
<Text style={{fontSize: 12, textAlign:"center"}}>Don't have an account? <Text style={{fontWeight: 700}}>Register</Text></Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
</KeyboardAvoidingView>
|
|
||||||
</SafeAreaView>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default login
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,83 +0,0 @@
|
||||||
import { StyleSheet, Text, View, SafeAreaView, KeyboardAvoidingView, Image, TextInput, Pressable, Alert } from 'react-native'
|
|
||||||
import React, { useState } from 'react'
|
|
||||||
import { Fontisto } from '@expo/vector-icons';
|
|
||||||
import { Entypo } from '@expo/vector-icons';
|
|
||||||
import { AntDesign } from '@expo/vector-icons';
|
|
||||||
import { useRouter } from 'expo-router';
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const register = () => {
|
|
||||||
const [name, setName] = useState('');
|
|
||||||
const [email, setEmail] = useState('');
|
|
||||||
const [password, setPassword] = useState('');
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const handleRegister = () => {
|
|
||||||
const user = {
|
|
||||||
name: name,
|
|
||||||
email: email,
|
|
||||||
password: password,
|
|
||||||
}
|
|
||||||
axios.post("http://localhost:3030/register", user).then((res) => {
|
|
||||||
console.log(res);
|
|
||||||
Alert.alert("Registration succeeded!");
|
|
||||||
setEmail('');
|
|
||||||
setPassword('');
|
|
||||||
setName('');
|
|
||||||
}).catch((error) => {
|
|
||||||
Alert.alert("Registration failed!");
|
|
||||||
console.log("error", error);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SafeAreaView style={{flex:1, backgroundColor: "white", alignItems: "center", justifyContent:"center"}}>
|
|
||||||
<View>
|
|
||||||
<View style={{alignItems: "center"}}>
|
|
||||||
<Image
|
|
||||||
style={{width: 150, height: 150, resizeMode: "containe"}}
|
|
||||||
source={{
|
|
||||||
uri:"./assets/images/logo.png",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<Text style={{fontSize: 24, fontWeight: 600, color: "#222831", marginTop: 20}}>Keep Tracking</Text>
|
|
||||||
</View>
|
|
||||||
<KeyboardAvoidingView>
|
|
||||||
<View style={{alignItems: "center"}}>
|
|
||||||
<Text style={{fontSize: 16, fontWeight: 600, color: "black", marginTop: 20}}>Register</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={{marginTop: 50}}>
|
|
||||||
<View style={{flexDirection: "row", justifyContent: "center", alignItems: "center", gap:5, backgroundColor: "#EEEEEE", paddingHorizontal:10, borderRadius:5}}>
|
|
||||||
<AntDesign name="user" size={16} color="#31363F" />
|
|
||||||
<TextInput value={name} onChangeText={(text) => setName(text)} style={{color: "#31363F", width:250, outlineStyle: 'none', marginVertical: 10, fontSize:email ? 14 : 14}} placeholder='Username'/>
|
|
||||||
</View>
|
|
||||||
<View style={{flexDirection: "row", justifyContent: "center", alignItems: "center", gap:5, backgroundColor: "#EEEEEE", paddingHorizontal:10, borderRadius:5, marginTop: 10}}>
|
|
||||||
<Fontisto name="email" size={16} color="#31363F" />
|
|
||||||
<TextInput value={email} onChangeText={(text) => setEmail(text)} style={{color: "#31363F", width:250, outlineStyle: 'none', marginVertical: 10, fontSize:email ? 14 : 14}} placeholder='Enter your email'/>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={{flexDirection: "row", justifyContent: "center", alignItems: "center", gap:5, backgroundColor: "#EEEEEE", paddingHorizontal:10, borderRadius:5, marginTop: 10}}>
|
|
||||||
<Entypo name="key" size={16} color="#31363F" />
|
|
||||||
<TextInput value={password} onChangeText={(text) => setPassword(text)} secureTextEntry={true} style={{color: "#31363F", width:250, outlineStyle: 'none', marginVertical: 10, fontSize:email ? 14 : 14}} placeholder='Enter your password'/>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={{marginTop: 50}}/>
|
|
||||||
|
|
||||||
<Pressable onPress={handleRegister} style={{backgroundColor: "#61677A", padding:10, borderRadius:5, alignItems: "center"}}>
|
|
||||||
<Text style={{color: "#D8D9DA", fontSize: 16, fontWeight: 600}}>Register</Text>
|
|
||||||
</Pressable>
|
|
||||||
|
|
||||||
<Pressable onPress={() => router.replace("/login")} style={{marginTop: 10}}>
|
|
||||||
<Text style={{fontSize: 12, textAlign:"center"}}>Already have an account? <Text style={{fontWeight: 700}}>Login</Text></Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
</KeyboardAvoidingView>
|
|
||||||
</SafeAreaView>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default register
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,53 +0,0 @@
|
||||||
import {Tabs} from "expo-router";
|
|
||||||
import { FontAwesome } from '@expo/vector-icons';
|
|
||||||
import { AntDesign } from '@expo/vector-icons';
|
|
||||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
|
||||||
|
|
||||||
export default function Layout(){
|
|
||||||
return(
|
|
||||||
<Tabs>
|
|
||||||
<Tabs.Screen
|
|
||||||
name="home"
|
|
||||||
options={{
|
|
||||||
tabBarLabel:"Home",
|
|
||||||
tabBarLabelStyle:{color:"black"},
|
|
||||||
headerShown: false,
|
|
||||||
tabBarIcon:({focused}) =>
|
|
||||||
focused? (
|
|
||||||
<FontAwesome name="tasks" size={24} color="black" />
|
|
||||||
) : (
|
|
||||||
<FontAwesome name="tasks" size={24} color="#45474B" />
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Tabs.Screen
|
|
||||||
name="calendar"
|
|
||||||
options={{
|
|
||||||
tabBarLabel:"calendar",
|
|
||||||
tabBarLabelStyle:{color:"black"},
|
|
||||||
headerShown: false,
|
|
||||||
tabBarIcon:({focused}) =>
|
|
||||||
focused? (
|
|
||||||
<AntDesign name="calendar" size={24} color="black" />
|
|
||||||
) : (
|
|
||||||
<AntDesign name="calendar" size={24} color="#45474B" />
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Tabs.Screen
|
|
||||||
name="profile"
|
|
||||||
options={{
|
|
||||||
tabBarLabel:"profile",
|
|
||||||
tabBarLabelStyle:{color:"black"},
|
|
||||||
headerShown: false,
|
|
||||||
tabBarIcon:({focused}) =>
|
|
||||||
focused? (
|
|
||||||
<MaterialCommunityIcons name="account-details" size={24} color="black" />
|
|
||||||
) : (
|
|
||||||
<MaterialCommunityIcons name="account-details" size={24} color="#45474B" />
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Tabs>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
import {Stack} from "expo-router";
|
|
||||||
|
|
||||||
export default function Layout(){
|
|
||||||
return(
|
|
||||||
<Stack screenOptions={{headerShown:false}}>
|
|
||||||
<Stack.Screen name="index"/>
|
|
||||||
</Stack>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import moment from 'moment';
|
|
||||||
import {Calendar} from "react-native-calendars";
|
|
||||||
import axios from "axios"
|
|
||||||
import { Feather } from '@expo/vector-icons';
|
|
||||||
import { Buffer } from 'buffer';
|
|
||||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
||||||
|
|
||||||
|
|
||||||
const getToken = async () => {
|
|
||||||
try {
|
|
||||||
let token = await AsyncStorage.getItem('authToken'); // get the authToken stored in AsyncStorage from login.js
|
|
||||||
let decodeToken = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
|
|
||||||
let userId = decodeToken.userId;
|
|
||||||
return userId;
|
|
||||||
} catch (e) {
|
|
||||||
// error reading value
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const index = () => {
|
|
||||||
const today = moment().format("YYYY-MM-DD");
|
|
||||||
const [selectedDate, setSelectedDate] = useState(today);
|
|
||||||
const [todos, setTodos] = useState([]);
|
|
||||||
|
|
||||||
const fetchCompletedTodos = () => {
|
|
||||||
try {
|
|
||||||
getToken().then( async (resp) => {
|
|
||||||
let userId = resp;
|
|
||||||
|
|
||||||
const res = await axios.get(`http://localhost:3030/users/${userId}/todos/completed/${selectedDate}`);
|
|
||||||
const completedTodos = res.data.completedTodos || [];
|
|
||||||
|
|
||||||
setTodos(completedTodos);
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error", error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
useEffect(() => {
|
|
||||||
fetchCompletedTodos();
|
|
||||||
|
|
||||||
}, [selectedDate]);
|
|
||||||
//Daypress
|
|
||||||
const handleDayPress = (day) => {
|
|
||||||
setSelectedDate(day.dateString)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={{flex:1, backgroundColor: "white"}}>
|
|
||||||
<Calendar onDayPress={handleDayPress}
|
|
||||||
theme = {{calendarBackground: "white", todayTextColor: 'red', arrowColor: "black",}}
|
|
||||||
markedDates={{[selectedDate]: {selected: true, selectedColor: "red"}}}
|
|
||||||
/>
|
|
||||||
{todos?.length > 0 && (
|
|
||||||
<View style={{marginTop: 20, marginHorizontal: 10}}>
|
|
||||||
<View style={{flexDirection:"row", alignItems: "center", gap: 10}}>
|
|
||||||
<Text style={{marginBottom: 20, fontSize: 16}}>You completed <Text style={{fontWeight: 600, color: "#61677A"}}>{todos.length}</Text> tasks</Text>
|
|
||||||
</View>
|
|
||||||
{todos.map((item, index) => (
|
|
||||||
<Pressable key={index} style={{backgroundColor: "#EEEEEE", marginBottom: 10, padding: 5, borderRadius: 5}}>
|
|
||||||
<View style={{flexDirection:"row", alignItems: "center", gap: 10}}>
|
|
||||||
<Feather name="check-circle" size={15} color="#1A5319" />
|
|
||||||
<Text style={{flex: 1, textDecorationLine: "line-through", color: "#1A5319"}}>{item.title}</Text>
|
|
||||||
</View>
|
|
||||||
</Pressable>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default index
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,13 +0,0 @@
|
||||||
import {Stack} from "expo-router";
|
|
||||||
import {ModalPortal} from "react-native-modals"
|
|
||||||
|
|
||||||
export default function Layout(){
|
|
||||||
return(
|
|
||||||
<>
|
|
||||||
<Stack screenOptions={{headerShown:false}}>
|
|
||||||
<Stack.Screen name="index"/>
|
|
||||||
</Stack>
|
|
||||||
<ModalPortal />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,240 +0,0 @@
|
||||||
import { Image, Pressable, ScrollView, StyleSheet, Text, TextInput, View } from 'react-native';
|
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import { AntDesign } from '@expo/vector-icons';
|
|
||||||
import { BottomModal, ModalContent, ModalTitle, SlideAnimation } from 'react-native-modals';
|
|
||||||
import { Entypo } from '@expo/vector-icons';
|
|
||||||
import { Feather } from '@expo/vector-icons';
|
|
||||||
import axios from "axios"
|
|
||||||
import moment from 'moment';
|
|
||||||
import { Buffer } from 'buffer';
|
|
||||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const index = () => {
|
|
||||||
const [todos, setTodos] = useState([]);
|
|
||||||
const [modalVisible, setModalVisible] = useState(false);
|
|
||||||
const [todo, setTodo] = useState('');
|
|
||||||
const [category, setCategory] = useState('all');
|
|
||||||
const [pendingTodos, setPendingTodos] = useState([]);
|
|
||||||
const [compledTodos, setCompletedTodos] = useState([]);
|
|
||||||
const [markCompleted, setMarkCompleted] = useState(false);
|
|
||||||
const todayDate = moment().format("MMM Do YYYY");
|
|
||||||
|
|
||||||
const getToken = async () => {
|
|
||||||
try {
|
|
||||||
let token = await AsyncStorage.getItem('authToken'); // get the authToken stored in AsyncStorage from login.js
|
|
||||||
let decodeToken = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
|
|
||||||
let userId = decodeToken.userId;
|
|
||||||
return userId;
|
|
||||||
} catch (e) {
|
|
||||||
// error reading value
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const addTodo = async() => {
|
|
||||||
try {
|
|
||||||
const todoData = {
|
|
||||||
title:todo,
|
|
||||||
category:category,
|
|
||||||
}
|
|
||||||
|
|
||||||
getToken().then((resp) => {
|
|
||||||
let userId = resp;
|
|
||||||
axios.post(`http://localhost:3030/todos/${userId}`, todoData).then((res) => {
|
|
||||||
})
|
|
||||||
|
|
||||||
}).catch((error) => {
|
|
||||||
console.log("Error", error);
|
|
||||||
})
|
|
||||||
await getUserTodos();
|
|
||||||
setModalVisible(false);
|
|
||||||
setTodo('');
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error", error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getUserTodos();
|
|
||||||
}, [markCompleted, modalVisible])
|
|
||||||
|
|
||||||
const getUserTodos = () => {
|
|
||||||
try {
|
|
||||||
getToken().then( async(resp) => {
|
|
||||||
let userId = resp;
|
|
||||||
const res = await axios.get(`http://localhost:3030/users/${userId}/todos`);
|
|
||||||
setTodos(res.data.todos);
|
|
||||||
|
|
||||||
const fetchTodos = res.data.todos || [];
|
|
||||||
const pending = fetchTodos.filter((todo) => todo.status !== "completed");
|
|
||||||
const completed = fetchTodos.filter((todo) => todo.status === "completed");
|
|
||||||
|
|
||||||
setPendingTodos(pending);
|
|
||||||
setCompletedTodos(completed);
|
|
||||||
})
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error", error)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const markTodocompleted = async (todoId) => {
|
|
||||||
try {
|
|
||||||
setMarkCompleted(true);
|
|
||||||
|
|
||||||
const res = await axios.patch(`http://localhost:3030/todos/${todoId}/complete`);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error", error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//data
|
|
||||||
const suggestion = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
todo: "Walk the dog"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
todo: "Go to the gym"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
todo: "Call mom"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
todo: "Get goceries"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
todo: "5 minute meditation"
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<View style={{marginHorizontal:20, marginVertical:20, alignItems: "center", flexDirection: "row", gap: 10}}>
|
|
||||||
<Pressable style={{backgroundColor: "#000000", paddingHorizontal:10, paddingVertical: 5, borderRadius:25, alignItems: "center", justifyContent: "center"}}>
|
|
||||||
<Text style={{color: "white", textAlign: "center"}}>All</Text>
|
|
||||||
</Pressable>
|
|
||||||
<Pressable style={{backgroundColor: "#000000", paddingHorizontal:10, paddingVertical: 5, borderRadius:25, alignItems: "center", justifyContent: "center"}}>
|
|
||||||
<Text style={{color: "white", textAlign: "center"}}>Work</Text>
|
|
||||||
</Pressable>
|
|
||||||
<Pressable style={{backgroundColor: "#000000", paddingHorizontal:10, paddingVertical: 5, borderRadius:25, alignItems: "center", justifyContent: "center", marginRight: "auto"}}>
|
|
||||||
<Text style={{color: "white", textAlign: "center"}}>Personal</Text>
|
|
||||||
</Pressable>
|
|
||||||
<Pressable onPress={() => setModalVisible(!modalVisible)}>
|
|
||||||
<AntDesign name="plus" size={24} color="black" />
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
<ScrollView style={{flex:1, backgroundColor: "white"}}>
|
|
||||||
<View style={{padding: 10}}>
|
|
||||||
{todos?.length > 0 ? (
|
|
||||||
<View>
|
|
||||||
{pendingTodos?.length > 0 &&
|
|
||||||
<>
|
|
||||||
<Text style={{fontSize: 20, fontWeight: 600, marginBottom: 10}}>{todayDate}</Text>
|
|
||||||
<Text style={{marginBottom: 20, fontSize: 16}}>You have <Text style={{fontWeight: 600, color: "#61677A"}}>{pendingTodos.length}</Text> tasks to do!</Text>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
{pendingTodos.map((item, index) => (
|
|
||||||
<Pressable key={index} style={{backgroundColor: "#EEEEEE", marginBottom: 10, padding: 5, borderRadius: 5}}>
|
|
||||||
<View style={{flexDirection:"row", alignItems: "center", gap: 10}}>
|
|
||||||
<Entypo onPress={() => markTodocompleted(item?._id)} name="circle" size={15} color="black" />
|
|
||||||
<Text style={{flex: 1}}>{item.title}</Text>
|
|
||||||
</View>
|
|
||||||
</Pressable>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{compledTodos?.length > 0 && (
|
|
||||||
<View style={{marginTop: 20}}>
|
|
||||||
<View style={{flexDirection:"row", alignItems: "center", gap: 10}}>
|
|
||||||
<Text style={{marginBottom: 20, fontSize: 16}}>You have completed <Text style={{fontWeight: 600, color: "#61677A"}}>{compledTodos.length}</Text> tasks</Text>
|
|
||||||
</View>
|
|
||||||
{compledTodos.map((item, index) => (
|
|
||||||
<Pressable key={index} style={{backgroundColor: "#EEEEEE", marginBottom: 10, padding: 5, borderRadius: 5}}>
|
|
||||||
<View style={{flexDirection:"row", alignItems: "center", gap: 10}}>
|
|
||||||
<Feather name="check-circle" size={15} color="#1A5319" />
|
|
||||||
<Text style={{flex: 1, textDecorationLine: "line-through", color: "#1A5319"}}>{item.title}</Text>
|
|
||||||
</View>
|
|
||||||
</Pressable>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<View style={{flex:1, justifyContent:"center", alignItems:"center", marginTop:150, marginLeft:"auto", marginRight:"auto"}}>
|
|
||||||
<Image
|
|
||||||
style={{width: 100, height: 100, resizeMode: "containe"}}
|
|
||||||
source={{
|
|
||||||
uri:"./assets/images/to-do.png",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text style={{fontSize:16, fontWeight:600, marginTop: 20, textAlign:"center"}}>Hooray! There is no tasks</Text>
|
|
||||||
<Pressable onPress={() => setModalVisible(!modalVisible)} style={{backgroundColor: "black", marginTop: 20, padding:5, borderRadius: 5}}>
|
|
||||||
<Text style={{fontSize:14, fontWeight:600, textAlign:"center", color: "white"}}>Add task <AntDesign name="plus" size={16} color="white" /></Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
<BottomModal
|
|
||||||
onBackdropPress={() => setModalVisible(!modalVisible)}
|
|
||||||
onHardwareBackPress={() => setModalVisible(!modalVisible)}
|
|
||||||
swipeDirection={['up', 'down']}
|
|
||||||
swipeThreshold={200}
|
|
||||||
modalTitle={<ModalTitle title="Add Task"/>}
|
|
||||||
modalAnimation={
|
|
||||||
new SlideAnimation({
|
|
||||||
slideFrom: 'bottom',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
visible={modalVisible}
|
|
||||||
onTouchOutside={() => setModalVisible(!modalVisible)}
|
|
||||||
>
|
|
||||||
<ModalContent style={{width:"100%", height:280}}>
|
|
||||||
<View style={{marginTop: 10, flexDirection: "row", alignItems: "center", gap: 10}}>
|
|
||||||
<TextInput value={todo} onChangeText={(text) => setTodo(text)} style={{padding:10, borderColor: "#61677A", borderRadius:5, borderWidth:1, flex:1, outlineStyle: 'none', color: "#31363F"}} placeholder='Add your new task'/>
|
|
||||||
<Entypo onPress={addTodo} name="add-to-list" size={24} color="black" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Text style={{marginTop: 10, fontWeight: 600}}>Category:</Text>
|
|
||||||
<View style={{flexDirection: "row", alignItems: "center", gap: 10, marginVertical: 10}}>
|
|
||||||
<Pressable onPress={() => setCategory('personal')} style={{backgroundColor: "#D8D9DA", padding: 5, borderRadius: 5,}}>
|
|
||||||
<Text>Personal</Text>
|
|
||||||
</Pressable>
|
|
||||||
|
|
||||||
<Pressable onPress={() => setCategory('work')} style={{backgroundColor: "#D8D9DA", padding: 5, borderRadius: 5}}>
|
|
||||||
<Text>Work</Text>
|
|
||||||
</Pressable>
|
|
||||||
|
|
||||||
<Pressable onPress={() => setCategory('house')} style={{backgroundColor: "#D8D9DA", padding: 5, borderRadius: 5}}>
|
|
||||||
<Text>House</Text>
|
|
||||||
</Pressable>
|
|
||||||
|
|
||||||
<Pressable onPress={() => setCategory('social')} style={{backgroundColor: "#D8D9DA", padding: 5, borderRadius: 5}}>
|
|
||||||
<Text>Social</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Text style={{marginTop: 10, fontWeight: 600}}>Suggestions:</Text>
|
|
||||||
<View style={{flexDirection: "row", alignItems: "center", gap: 10, marginVertical: 10, flexWrap: "wrap"}}>
|
|
||||||
{suggestion?.map((item, index) =>
|
|
||||||
<Pressable onPress={() => setTodo(item?.todo)} key={index} style={{backgroundColor: "#EEEEEE", padding: 5, borderRadius: 5}}>
|
|
||||||
<Text>{item.todo}</Text>
|
|
||||||
</Pressable>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</ModalContent>
|
|
||||||
</BottomModal>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default index
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,9 +0,0 @@
|
||||||
import {Stack} from "expo-router";
|
|
||||||
|
|
||||||
export default function Layout(){
|
|
||||||
return(
|
|
||||||
<Stack screenOptions={{headerShown:false}}>
|
|
||||||
<Stack.Screen name="index"/>
|
|
||||||
</Stack>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
import { Dimensions, Image, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import axios from "axios";
|
|
||||||
import {BarChart} from "react-native-chart-kit";
|
|
||||||
import { Buffer } from 'buffer';
|
|
||||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
||||||
|
|
||||||
const getToken = async () => {
|
|
||||||
try {
|
|
||||||
let token = await AsyncStorage.getItem('authToken'); // get the authToken stored in AsyncStorage from login.js
|
|
||||||
let decodeToken = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
|
|
||||||
let userId = decodeToken.userId;
|
|
||||||
return userId;
|
|
||||||
} catch (e) {
|
|
||||||
// error reading value
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const index = () => {
|
|
||||||
const [completedTasks, setCompletedTasks] = useState(0);
|
|
||||||
const [pendingTasks, setPendingTasks] = useState(0);
|
|
||||||
|
|
||||||
const fetchTaskData = () => {
|
|
||||||
try {
|
|
||||||
|
|
||||||
getToken().then( async (resp) => {
|
|
||||||
let userId = resp;
|
|
||||||
|
|
||||||
const res = await axios.get(`http://localhost:3030/users/${userId}/todos/count`);
|
|
||||||
const {totalCompletedTodos, totalPendingTodos} = res.data;
|
|
||||||
|
|
||||||
setCompletedTasks(totalCompletedTodos);
|
|
||||||
setPendingTasks(totalPendingTodos);
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error", error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchTaskData();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<View style={{marginHorizontal:20, marginVertical:20, alignItems: "center", flexDirection: "row", gap: 10}}>
|
|
||||||
<Pressable style={{marginRight: "auto"}}>
|
|
||||||
<Text style={{color: "black", textAlign: "center", fontSize: 20, fontWeight: 600}}>Keep Tracking</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
<View style={{padding: 10, flex: 1, backgroundColor: "white"}}>
|
|
||||||
<View style={{marginTop: 10, marginHorizontal:10}}>
|
|
||||||
<Text style={{fontSize: 16, fontWeight: 600}}>Overview</Text>
|
|
||||||
<View style={{flexDirection: "row", alignItems: "center", gap: 10, marginVertical: 10}}>
|
|
||||||
<View style={{padding:10, backgroundColor: "#E8C4C4", borderRadius: 5, flex:1, justifyContent: "center", alignItems: "center"}}>
|
|
||||||
<Text style={{color: "#CE7777", fontWeight: 600}}>{pendingTasks}</Text>
|
|
||||||
<Text style={{color: "#CE7777", fontWeight: 600}}>Pending Tasks</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={{padding:10, backgroundColor: "#C8DBBE", borderRadius: 5, flex:1, justifyContent: "center", alignItems: "center"}}>
|
|
||||||
<Text style={{color: "#829460", fontWeight: 600}}>{completedTasks}</Text>
|
|
||||||
<Text style={{color: "#829460", fontWeight: 600}}>Completed Tasks</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
{/*========== chart =========*/}
|
|
||||||
<BarChart
|
|
||||||
data={{
|
|
||||||
labels: ["Pending", "Completed"],
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
data: [pendingTasks, completedTasks],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}}
|
|
||||||
width={Dimensions.get("window").width - 20}
|
|
||||||
height={200}
|
|
||||||
yAxisInterval={2}
|
|
||||||
chartConfig={{
|
|
||||||
backgroundColor: "#BFACE2",
|
|
||||||
backgroundGradientFrom: "#BCCEF8",
|
|
||||||
backgroundGradientTo: "#F3E8FF",
|
|
||||||
decimalPlaces: 2,
|
|
||||||
color: (opacity = 1) => `rgba(106, 90, 205, ${opacity})`,
|
|
||||||
labelColor: (opacity = 1) => `rgba(108, 56, 172, ${opacity})`,
|
|
||||||
style: {
|
|
||||||
borderRadius: 5
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
borderRadius: 10,
|
|
||||||
marginTop: 10
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default index
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { StyleSheet, Text, View } from "react-native";
|
|
||||||
import React from 'react';
|
|
||||||
import { Redirect } from "expo-router";
|
|
||||||
|
|
||||||
const index = () => {
|
|
||||||
return (
|
|
||||||
<Redirect href="/(authenticate)/login"/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default index
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 24 KiB |
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
|
@ -1,6 +0,0 @@
|
||||||
module.exports = function (api) {
|
|
||||||
api.cache(true);
|
|
||||||
return {
|
|
||||||
presets: ['babel-preset-expo'],
|
|
||||||
};
|
|
||||||
};
|
|
19034
todo_app/package-lock.json
generated
19034
todo_app/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,55 +0,0 @@
|
||||||
{
|
|
||||||
"name": "todo_app",
|
|
||||||
"main": "expo-router/entry",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"scripts": {
|
|
||||||
"start": "expo start",
|
|
||||||
"reset-project": "node ./scripts/reset-project.js",
|
|
||||||
"android": "expo start --android",
|
|
||||||
"ios": "expo start --ios",
|
|
||||||
"web": "expo start --web",
|
|
||||||
"test": "jest --watchAll",
|
|
||||||
"lint": "expo lint"
|
|
||||||
},
|
|
||||||
"jest": {
|
|
||||||
"preset": "jest-expo"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@expo/vector-icons": "^14.0.2",
|
|
||||||
"@react-native-async-storage/async-storage": "1.23.1",
|
|
||||||
"@react-navigation/native": "^6.0.2",
|
|
||||||
"axios": "^1.7.2",
|
|
||||||
"expo": "~51.0.20",
|
|
||||||
"expo-constants": "~16.0.2",
|
|
||||||
"expo-font": "~12.0.8",
|
|
||||||
"expo-linking": "~6.3.1",
|
|
||||||
"expo-router": "~3.5.18",
|
|
||||||
"expo-splash-screen": "~0.27.5",
|
|
||||||
"expo-status-bar": "~1.12.1",
|
|
||||||
"expo-system-ui": "~3.0.7",
|
|
||||||
"expo-web-browser": "~13.0.3",
|
|
||||||
"moment": "^2.30.1",
|
|
||||||
"react": "18.2.0",
|
|
||||||
"react-dom": "18.2.0",
|
|
||||||
"react-native": "0.74.3",
|
|
||||||
"react-native-calendars": "^1.1305.0",
|
|
||||||
"react-native-chart-kit": "^6.12.0",
|
|
||||||
"react-native-gesture-handler": "~2.16.1",
|
|
||||||
"react-native-modals": "^0.22.3",
|
|
||||||
"react-native-reanimated": "~3.10.1",
|
|
||||||
"react-native-safe-area-context": "4.10.1",
|
|
||||||
"react-native-screens": "3.31.1",
|
|
||||||
"react-native-web": "~0.19.10"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/core": "^7.20.0",
|
|
||||||
"@types/jest": "^29.5.12",
|
|
||||||
"@types/react": "~18.2.45",
|
|
||||||
"@types/react-test-renderer": "^18.0.7",
|
|
||||||
"jest": "^29.2.1",
|
|
||||||
"jest-expo": "~51.0.3",
|
|
||||||
"react-test-renderer": "18.2.0",
|
|
||||||
"typescript": "~5.3.3"
|
|
||||||
},
|
|
||||||
"private": true
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "expo/tsconfig.base",
|
|
||||||
"compilerOptions": {
|
|
||||||
"strict": true,
|
|
||||||
"paths": {
|
|
||||||
"@/*": [
|
|
||||||
"./*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"**/*.ts",
|
|
||||||
"**/*.tsx",
|
|
||||||
".expo/types/**/*.ts",
|
|
||||||
"expo-env.d.ts"
|
|
||||||
]
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue