Skip to content

Commit

Permalink
feat(frontend): add habit with https request
Browse files Browse the repository at this point in the history
close #16
  • Loading branch information
looppoolloop committed Mar 9, 2024
1 parent 27f095b commit 2f4c0b4
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 32 deletions.
3 changes: 2 additions & 1 deletion client/memo-minder-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.0",
"react-scripts": "^5.0.1",
"web-vitals": "^2.1.4"
"web-vitals": "^2.1.4",
"axios": "^0.24.0"
},
"scripts": {
"start": "react-scripts start",
Expand Down
62 changes: 60 additions & 2 deletions client/memo-minder-web/src/App.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import axios from 'axios';
import React, { useState, useEffect } from 'react';
import {
createBrowserRouter,
Expand All @@ -15,7 +16,7 @@ import ShopArea from "./component/shopArea/ShopArea";
import ChallengeArea from './component/challengeArea/ChallengeArea';
import Popup from './component/popup/Popup';


import {BASE_URL, STATUS_CODE, SERVER_API} from './utils/constants'
// function to create default items for TaskArea
const createDefaultItem = (content, options = {}) => ({
id: Date.now(),
Expand Down Expand Up @@ -127,7 +128,64 @@ function App() {
const [todos, setTodos] = useState(() => JSON.parse(localStorage.getItem('todos')) || [defaultTodo]);
const [rewards, setRewards] = useState(() => JSON.parse(localStorage.getItem('rewards')) || [defaultReward]);

const addHabit = (habit) => {setHabits(prev => [...prev, habit])};
// TODO: 账号信息如何管理?全局变量?Context?props传 随用随取?
// TODO: task数据从server获取后 增删改的回调函数逻辑是否可以挪回组件内部
let validToken;

const login = async(username, password) => {
try {
const response = await axios.post(BASE_URL + SERVER_API.LOGIN, {
// TODO: delete the stub username/psw when login is integrated with backend
'username': username ?? 'Yue',
'password': password ?? 'yue@memominder'
});
console.debug('login success:', response.status);
return response?.data?.token;
} catch (error) {
return Promise.reject(error)
}
};

let retryCount = 0;

const addHabitToServer = async (habit) => {
try {
console.debug('addHabitToServer:', habit);
if (!habit?.content || !habit?.notes) {
console.warn('invalid habit, no need to post');
return;
}
if (!validToken) {
validToken = await login();
}
const response = await axios.post(BASE_URL + SERVER_API.ADD_HABIT, {
'title': habit.content,
'type': habit.positive && habit.negative ? 'both' : !habit.positive && !habit.negative ? 'neutral' : habit.positive ? 'positive' : 'negative',
'note': habit.notes
}, {
headers: {
'Authorization': validToken,
'Content-Type': 'application/json'
}
});
console.debug('post new habit success:', response.status);
} catch (error) {
if (error.response.status === STATUS_CODE.UNAUTHORIZED && retryCount < 1) {
validToken = null;
retryCount++;
addHabitToServer(habit);
} else {
retryCount = 0;
}
console.warn('post new habit error:', error);
}
};

const addHabit = (habit) => {
setHabits(prev => [...prev, habit])
addHabitToServer(habit);
};

const addDaily = (daily) => {setDailies(prev => [...prev, daily])};
const addTodo = (todo) => {setTodos(prev => [...prev, todo]);};
const addReward = (reward) => {setRewards(prev => [...prev, reward]);};
Expand Down
14 changes: 12 additions & 2 deletions client/memo-minder-web/src/component/taskButton/TaskButton.css
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,25 @@

.round-button {
border-radius: 50%;
width: 30px;
height: 30px;
width: 50px;
height: 50px;
margin-right: 10px;
margin-top: 20px;
}

.round-button.selected {
background-color: #d4a3ff
}

.round-button.unselected {
background-color: #f9ecfb
}

.dialog-description {
display: flex;
justify-content: center;
margin-top: 5px;
color: #fff;
}

.dialog-description span {
Expand Down
76 changes: 49 additions & 27 deletions client/memo-minder-web/src/component/taskButton/TaskButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ import React, { useState } from 'react';
import './TaskButton.css';
import TaskDialog from './TaskDialog';

const TaskButton = ({ onAddHabit, onAddDaily, onAddTodo, onAddReward}) => {
const TaskButton = ({ onAddHabit, onAddDaily, onAddTodo, onAddReward }) => {
const [showMenu, setShowMenu] = useState(false);
const [showDialog, setShowDialog] = useState(false);
const [dialogTitle, setDialogTitle] = useState('');
const [habitTitle, setHabitTitle] = useState('Add a title');
const [habitNotes, setHabitNotes] = useState('Add notes');
const [habitTitle, setHabitTitle] = useState('');
const defaultTitle = 'Add a title';
const [habitNotes, setHabitNotes] = useState('');
const defaultNotes = 'Add notes';
const [rewardPrice, setRewardPrice] = useState();
const defaultPrice = 10;
const [positive, setPositive] = useState(true);
const [negative, setNegative] = useState(true);

const handleButtonClick = () => {
setShowMenu(!showMenu);
Expand All @@ -31,37 +37,37 @@ const TaskButton = ({ onAddHabit, onAddDaily, onAddTodo, onAddReward}) => {
createFunction = onAddHabit;
newItem = {
id: Date.now(),
content: habitTitle,
notes: habitNotes,
positive: true,
negative: true
content: habitTitle || defaultTitle,
notes: habitNotes || defaultNotes,
positive: positive,
negative: negative
};
break;
case 'Create Daily':
createFunction = onAddDaily;
newItem = {
id: Date.now(),
content: habitTitle,
notes: habitNotes,
completed: false
content: habitTitle || defaultTitle,
notes: habitNotes || defaultNotes,
completed: false
};
break;
case 'Create To Do':
createFunction = onAddTodo;
newItem = {
id: Date.now(),
content: habitTitle,
notes: habitNotes,
content: habitTitle || defaultTitle,
notes: habitNotes || defaultNotes,
completed: false
};
break;
case 'Create Reward':
createFunction = onAddReward;
newItem = {
id: Date.now(),
content: habitTitle,
notes: habitNotes,
price: 10
content: habitTitle || defaultTitle,
notes: habitNotes || defaultNotes,
price: rewardPrice || defaultPrice
};
break;
default:
Expand All @@ -76,7 +82,14 @@ const TaskButton = ({ onAddHabit, onAddDaily, onAddTodo, onAddReward}) => {
const handleCancel = () => {
console.log('Canceling...');
setShowDialog(false);
}

const handlePositive = () => {
setPositive(!positive);
};

const handleNegative = () => {
setNegative(!negative);
};

return (
Expand Down Expand Up @@ -105,7 +118,7 @@ const TaskButton = ({ onAddHabit, onAddDaily, onAddTodo, onAddReward}) => {
<img src="/reward.png" alt="Reward" className="menu-icon" />
Reward
</button>

</div>
)}

Expand All @@ -116,23 +129,32 @@ const TaskButton = ({ onAddHabit, onAddDaily, onAddTodo, onAddReward}) => {
<div className="input-container">
<label>Title*:</label>
<br />
<input type="text" className="habit-input" value={habitTitle} onChange={(e) => setHabitTitle(e.target.value)} />
<input type="text" className="habit-input" value={habitTitle} placeholder={defaultTitle} onChange={(e) => setHabitTitle(e.target.value)} />
</div>
<div className="input-container">
<label>Notes:</label>
<br />
<textarea className="habit-input" value={habitNotes} onChange={(e) => setHabitNotes(e.target.value)} />
<textarea className="habit-input" value={habitNotes} placeholder={defaultNotes} onChange={(e) => setHabitNotes(e.target.value)} />
</div>
{dialogTitle === 'Create Reward' && (
<div className="input-container">
<label>Price:</label>
<br />
<input type="number" className="habit-input" value={rewardPrice} placeholder={defaultPrice} onChange={(e) => setRewardPrice(e.target.value)} />
</div>)}

{/* TODO: move it to children */}
{/* <div className="dialog-buttons-circle">
<button className="round-button">+</button>
<button className="round-button">-</button>
</div>
<div className="dialog-description">
<span>Positive</span>
<span>Negative</span>
</div> */}
{dialogTitle === 'Create Habit' && (
<div>
<div className="dialog-buttons-circle">
<button className={`round-button ${positive ? 'selected' : 'unselected'}`} onClick={handlePositive}>+</button>
<button className={`round-button ${negative ? 'selected' : 'unselected'}`} onClick={handleNegative}>-</button>
</div>
<div className="dialog-description">
<span>Positive</span>
<span>Negative</span>
</div>
</div>
)}
</TaskDialog>
</div>
)}
Expand Down
12 changes: 12 additions & 0 deletions client/memo-minder-web/src/utils/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const BASE_URL = 'https://memo-minder.onrender.com';

export const STATUS_CODE = {
SUCCESS: 200,
ADD_HABIT_SUCCESS: 201,
UNAUTHORIZED: 401,
};

export const SERVER_API = {
LOGIN: '/api/login',
ADD_HABIT: '/api/habits'
}

0 comments on commit 2f4c0b4

Please sign in to comment.