From a8c14f13313f09aef5a86e09875d7ba929622bce Mon Sep 17 00:00:00 2001 From: keannu125 Date: Wed, 1 Mar 2023 23:28:31 +0800 Subject: [PATCH 01/13] Added token to header for get APIs to support notes by user --- src/Components/Api/Api.tsx | 27 ++++++++++++++++++++++----- src/Components/Notes/Notes.tsx | 17 +++++++++++++---- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/Components/Api/Api.tsx b/src/Components/Api/Api.tsx index a9478b3..be99e4c 100644 --- a/src/Components/Api/Api.tsx +++ b/src/Components/Api/Api.tsx @@ -3,9 +3,16 @@ import axios from "axios"; // Note APIs export function GetNotes() { - return axios.get("http://localhost:8000/api/v1/notes/").then((response) => { - return response.data; - }); + const token = JSON.parse(localStorage.getItem("token") || ""); + return axios + .get("http://localhost:8000/api/v1/notes/", { + headers: { + Authorization: "Token " + token, + }, + }) + .then((response) => { + return response.data; + }); } export interface note { @@ -14,15 +21,25 @@ export interface note { } export function AddNote(note: note) { + const token = JSON.parse(localStorage.getItem("token") || ""); return axios - .post("http://localhost:8000/api/v1/notes/", note) + .post("http://localhost:8000/api/v1/notes/", note, { + headers: { + Authorization: "Token " + token, + }, + }) .then((response) => { return response.data; }); } export function DeleteNote(id: number) { - return axios.delete("http://localhost:8000/api/v1/notes/" + id + "/"); + const token = JSON.parse(localStorage.getItem("token") || ""); + return axios.delete("http://localhost:8000/api/v1/notes/" + id + "/", { + headers: { + Authorization: "Token " + token, + }, + }); } // User APIs diff --git a/src/Components/Notes/Notes.tsx b/src/Components/Notes/Notes.tsx index 630a34a..96b7ada 100644 --- a/src/Components/Notes/Notes.tsx +++ b/src/Components/Notes/Notes.tsx @@ -5,6 +5,7 @@ import Note from "../Note/Note"; import { Button } from "@mui/material"; import { useQuery } from "react-query"; import { GetNotes } from "../Api/Api"; +import { useSelector } from "react-redux"; export default function Notes() { const navigate = useNavigate(); @@ -13,21 +14,29 @@ export default function Notes() { isLoading, error, } = useQuery("notes", GetNotes, { retry: 0 }); + const logged_in = useSelector( + (state: { Login: { logged_in: boolean } }) => state.Login.logged_in + ); + if (!logged_in) { + return ( +
+

Please login to use Clip Notes

+
+ ); + } if (error) { return (

Error contacting Notes server

); - } - if (isLoading) { + } else if (isLoading) { return (

Loading Notes...

); - } - if (notes.length === 0) { + } else if (notes.length === 0) { return (

No notes exist yet

From 132dfa496df45ccf4ef60a1abbaaa267b77bd13d Mon Sep 17 00:00:00 2001 From: keannu125 Date: Thu, 2 Mar 2023 00:16:28 +0800 Subject: [PATCH 02/13] Separated typescript interfaces into its own file and polished and cleaned up overall code --- src/Components/Api/Api.tsx | 34 +++++---------- src/Components/AppIcon/AppIcon.tsx | 8 +--- src/Components/Header/Header.tsx | 1 - src/Components/HomeIcon/HomeIcon.tsx | 8 +--- src/Components/LoginButton/LoginButton.tsx | 17 ++------ src/Components/Note/Note.tsx | 9 +--- src/Components/Notes/Notes.tsx | 5 +-- src/Interfaces/Interfaces.tsx | 51 ++++++++++++++++++++++ src/Routes/Activation/Activation.tsx | 9 ++-- src/Routes/Login/Login.tsx | 6 +-- src/Routes/Register/Register.tsx | 14 ++---- 11 files changed, 83 insertions(+), 79 deletions(-) create mode 100644 src/Interfaces/Interfaces.tsx diff --git a/src/Components/Api/Api.tsx b/src/Components/Api/Api.tsx index be99e4c..000b057 100644 --- a/src/Components/Api/Api.tsx +++ b/src/Components/Api/Api.tsx @@ -1,4 +1,10 @@ import axios from "axios"; +import { + ActivationParams, + AddNoteParams, + LoginParams, + RegistrationParams, +} from "../../Interfaces/Interfaces"; // Note APIs @@ -15,12 +21,7 @@ export function GetNotes() { }); } -export interface note { - title: string; - content: string; -} - -export function AddNote(note: note) { +export function AddNote(note: AddNoteParams) { const token = JSON.parse(localStorage.getItem("token") || ""); return axios .post("http://localhost:8000/api/v1/notes/", note, { @@ -43,13 +44,8 @@ export function DeleteNote(id: number) { } // User APIs -export interface register { - email: string; - username: string; - password: string; -} -export function UserRegister(register: register) { +export function UserRegister(register: RegistrationParams) { return axios .post("http://localhost:8000/api/v1/accounts/users/", register) .then(async (response) => { @@ -62,12 +58,7 @@ export function UserRegister(register: register) { }); } -export interface user { - username: string; - password: string; -} - -export function UserLogin(user: user) { +export function UserLogin(user: LoginParams) { return axios .post("http://localhost:8000/api/v1/accounts/token/login/", user) .then(async (response) => { @@ -101,12 +92,7 @@ export function UserInfo() { }); } -export interface activation { - uid: string; - token: string; -} - -export function UserActivate(activation: activation) { +export function UserActivate(activation: ActivationParams) { return axios .post("http://localhost:8000/api/v1/accounts/users/activation/", activation) .then(async (response) => { diff --git a/src/Components/AppIcon/AppIcon.tsx b/src/Components/AppIcon/AppIcon.tsx index 56d5c80..78e60e2 100644 --- a/src/Components/AppIcon/AppIcon.tsx +++ b/src/Components/AppIcon/AppIcon.tsx @@ -1,11 +1,7 @@ import * as React from "react"; +import { IconProps } from "../../Interfaces/Interfaces"; -export interface props { - size: number; - color: string; -} - -export default function AppIcon(props: props) { +export default function AppIcon(props: IconProps) { return ( <> -
state.Login.logged_in + const logged_in = useSelector((state: LoginState) => state.Login.logged_in); + const logged_in_user = useSelector( + (state: LoggedInUserState) => state.LoggedInUser.value ); - const logged_in_user = useSelector((state: user) => state.LoggedInUser.value); const navigate = useNavigate(); if (!logged_in) { return ( diff --git a/src/Components/Note/Note.tsx b/src/Components/Note/Note.tsx index 153e424..b8bd090 100644 --- a/src/Components/Note/Note.tsx +++ b/src/Components/Note/Note.tsx @@ -3,14 +3,9 @@ import styles from "../../styles"; import { Button } from "@mui/material"; import { useMutation, useQueryClient } from "react-query"; import { DeleteNote } from "../Api/Api"; +import { NoteProps } from "../../Interfaces/Interfaces"; -export interface props { - title: string; - content: string; - id: number; - date_created: string; -} -export default function Note(props: props) { +export default function Note(props: NoteProps) { const queryClient = useQueryClient(); const mutation = useMutation({ mutationFn: DeleteNote, diff --git a/src/Components/Notes/Notes.tsx b/src/Components/Notes/Notes.tsx index 96b7ada..e1c2d2a 100644 --- a/src/Components/Notes/Notes.tsx +++ b/src/Components/Notes/Notes.tsx @@ -6,6 +6,7 @@ import { Button } from "@mui/material"; import { useQuery } from "react-query"; import { GetNotes } from "../Api/Api"; import { useSelector } from "react-redux"; +import { LoginState } from "../../Interfaces/Interfaces"; export default function Notes() { const navigate = useNavigate(); @@ -14,9 +15,7 @@ export default function Notes() { isLoading, error, } = useQuery("notes", GetNotes, { retry: 0 }); - const logged_in = useSelector( - (state: { Login: { logged_in: boolean } }) => state.Login.logged_in - ); + const logged_in = useSelector((state: LoginState) => state.Login.logged_in); if (!logged_in) { return (
diff --git a/src/Interfaces/Interfaces.tsx b/src/Interfaces/Interfaces.tsx new file mode 100644 index 0000000..ea68b14 --- /dev/null +++ b/src/Interfaces/Interfaces.tsx @@ -0,0 +1,51 @@ +// Redux Interfaces +export interface LoginState { + Login: { logged_in: boolean }; +} + +export interface LoggedInUserState { + LoggedInUser: { + value: { + email: string; + id: number; + username: string; + }; + }; +} + +// Component Props Interfaces + +export interface NoteProps { + title: string; + content: string; + id: number; + date_created: string; +} + +export interface IconProps { + size: number; + color: string; +} + +// API Interfaces + +export interface RegistrationParams { + email: string; + username: string; + password: string; +} + +export interface LoginParams { + username: string; + password: string; +} + +export interface ActivationParams { + uid: string; + token: string; +} + +export interface AddNoteParams { + title: string; + content: string; +} diff --git a/src/Routes/Activation/Activation.tsx b/src/Routes/Activation/Activation.tsx index 972baf5..18d1629 100644 --- a/src/Routes/Activation/Activation.tsx +++ b/src/Routes/Activation/Activation.tsx @@ -3,15 +3,12 @@ import Header from "../../Components/Header/Header"; import { useParams } from "react-router-dom"; import { useEffect, useState } from "react"; import { UserActivate } from "../../Components/Api/Api"; +import { ActivationParams } from "../../Interfaces/Interfaces"; -export interface activation { - uid: string; - token: string; -} export default function Activation() { let { uid, token } = useParams(); const [status, setStatus] = useState(0); - async function verify(activation: activation) { + async function verify(activation: ActivationParams) { let status = await UserActivate(activation); if (status) { setStatus(1); @@ -23,7 +20,7 @@ export default function Activation() { if (uid && token) { verify({ uid, token }); } - }, []); + }, [uid, token]); if (status === 1) { return (
diff --git a/src/Routes/Login/Login.tsx b/src/Routes/Login/Login.tsx index a4ed28b..371e094 100644 --- a/src/Routes/Login/Login.tsx +++ b/src/Routes/Login/Login.tsx @@ -7,7 +7,7 @@ import { useState } from "react"; import { Button } from "@mui/material"; import { UserInfo, UserLogin } from "../../Components/Api/Api"; -import { useSelector, useDispatch } from "react-redux"; +import { useDispatch } from "react-redux"; import { SetUser } from "../../Features/Redux/Slices/LoggedInUserSlice/LoggedInUserSlice"; import { SetLoggedIn } from "../../Features/Redux/Slices/LoginSlice/LoginSlice"; @@ -29,7 +29,7 @@ export default function Login() {
{ + onChange={(e: React.ChangeEvent) => { setUser({ ...user, username: e.target.value }); }} maxLength={20} @@ -41,7 +41,7 @@ export default function Login() { { + onChange={(e: React.ChangeEvent) => { setUser({ ...user, password: e.target.value }); }} maxLength={20} diff --git a/src/Routes/Register/Register.tsx b/src/Routes/Register/Register.tsx index ecff80a..147f2f0 100644 --- a/src/Routes/Register/Register.tsx +++ b/src/Routes/Register/Register.tsx @@ -1,16 +1,12 @@ import * as React from "react"; import styles from "../../styles"; -import { useNavigate } from "react-router-dom"; import Header from "../../Components/Header/Header"; import { useState } from "react"; import { Button } from "@mui/material"; -import { UserInfo, UserLogin } from "../../Components/Api/Api"; - import { UserRegister } from "../../Components/Api/Api"; export default function Register() { - const navigate = useNavigate(); const [user, setUser] = useState({ email: "", username: "", @@ -27,7 +23,7 @@ export default function Register() {
{ + onChange={(e: React.ChangeEvent) => { setUser({ ...user, email: e.target.value }); }} maxLength={20} @@ -38,7 +34,7 @@ export default function Register() {
{ + onChange={(e: React.ChangeEvent) => { setUser({ ...user, username: e.target.value }); }} maxLength={20} @@ -50,7 +46,7 @@ export default function Register() { { + onChange={(e: React.ChangeEvent) => { setUser({ ...user, password: e.target.value }); }} maxLength={20} @@ -61,9 +57,7 @@ export default function Register() { variant="contained" onClick={async () => { setUser({ - email: "", - username: "", - password: "", + ...user, }); if (await UserRegister(user)) { setFeedback( From 2e6c5fbef80e761cfdb7828a640a471c97aa63f7 Mon Sep 17 00:00:00 2001 From: keannu125 Date: Thu, 2 Mar 2023 00:43:26 +0800 Subject: [PATCH 03/13] Show owner on note --- src/Components/Note/Note.tsx | 3 ++- src/Components/Notes/Notes.tsx | 2 ++ src/Interfaces/Interfaces.tsx | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Components/Note/Note.tsx b/src/Components/Note/Note.tsx index b8bd090..6924a83 100644 --- a/src/Components/Note/Note.tsx +++ b/src/Components/Note/Note.tsx @@ -16,7 +16,8 @@ export default function Note(props: NoteProps) { return (
-

{props.title}

+

Owner: {props.owner}

+

Title: {props.title}

{props.content}

diff --git a/src/Components/Notes/Notes.tsx b/src/Components/Notes/Notes.tsx index e1c2d2a..b275869 100644 --- a/src/Components/Notes/Notes.tsx +++ b/src/Components/Notes/Notes.tsx @@ -58,6 +58,7 @@ export default function Notes() { {notes.map( ( note: { + owner: string; title: string; content: string; id: number; @@ -72,6 +73,7 @@ export default function Notes() { title={note.title} content={note.content} date_created={note.date_created} + owner={note.owner} /> ); } diff --git a/src/Interfaces/Interfaces.tsx b/src/Interfaces/Interfaces.tsx index ea68b14..7ec33f0 100644 --- a/src/Interfaces/Interfaces.tsx +++ b/src/Interfaces/Interfaces.tsx @@ -20,6 +20,7 @@ export interface NoteProps { content: string; id: number; date_created: string; + owner: string; } export interface IconProps { From d73da74004894353116d911f8b35edb893ee932c Mon Sep 17 00:00:00 2001 From: keannu125 Date: Fri, 3 Mar 2023 23:46:07 +0800 Subject: [PATCH 04/13] Made note input and note body preview bigger --- src/Components/Note/Note.tsx | 6 +++++- src/Routes/NewNote/NewNote.tsx | 16 +++++++++------- src/styles.tsx | 4 +++- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Components/Note/Note.tsx b/src/Components/Note/Note.tsx index 6924a83..bb2c6df 100644 --- a/src/Components/Note/Note.tsx +++ b/src/Components/Note/Note.tsx @@ -19,7 +19,11 @@ export default function Note(props: NoteProps) {

Owner: {props.owner}

Title: {props.title}

-

{props.content}

+