Format code with Prettier

This commit is contained in:
sosokker 2023-11-13 23:51:17 +07:00
parent bac1f96ad8
commit 038a0c84b7
21 changed files with 310 additions and 385 deletions

View File

@ -1,10 +1,10 @@
import React from 'react'; import React from "react";
import { Navigate, Outlet } from 'react-router-dom'; import { Navigate, Outlet } from "react-router-dom";
import IsAuthenticated from './hooks/authentication/IsAuthenticated'; import IsAuthenticated from "./hooks/authentication/IsAuthenticated";
const PrivateRoute = () => { const PrivateRoute = () => {
const auth = IsAuthenticated(); const auth = IsAuthenticated();
return auth ? <Outlet /> : <Navigate to="/login" />; return auth ? <Outlet /> : <Navigate to="/login" />;
} };
export default PrivateRoute; export default PrivateRoute;

View File

@ -1,11 +1,11 @@
import axios from 'axios'; import axios from "axios";
const ApiUpdateUserProfile = async (formData) => { const ApiUpdateUserProfile = async formData => {
try { try {
const response = await axios.post('http://127.0.1:8000/api/user/update/', formData, { const response = await axios.post("http://127.0.1:8000/api/user/update/", formData, {
headers: { headers: {
'Authorization': "Bearer " + localStorage.getItem('access_token'), Authorization: "Bearer " + localStorage.getItem("access_token"),
'Content-Type': 'multipart/form-data', "Content-Type": "multipart/form-data",
}, },
}); });
@ -13,7 +13,7 @@ const ApiUpdateUserProfile = async (formData) => {
return response.data; return response.data;
} catch (error) { } catch (error) {
console.error('Error updating user profile:', error); console.error("Error updating user profile:", error);
throw error; throw error;
} }
}; };

View File

@ -1,13 +1,13 @@
import axios from 'axios'; import axios from "axios";
import { redirect } from 'react-router-dom'; import { redirect } from "react-router-dom";
const axiosInstance = axios.create({ const axiosInstance = axios.create({
baseURL: 'http://127.0.0.1:8000/api/', baseURL: "http://127.0.0.1:8000/api/",
timeout: 5000, timeout: 5000,
headers: { headers: {
'Authorization': "Bearer " + localStorage.getItem('access_token'), Authorization: "Bearer " + localStorage.getItem("access_token"),
'Content-Type': 'application/json', "Content-Type": "application/json",
'accept': 'application/json', accept: "application/json",
}, },
}); });
@ -16,28 +16,30 @@ axiosInstance.interceptors.response.use(
response => response, response => response,
error => { error => {
const originalRequest = error.config; const originalRequest = error.config;
const refresh_token = localStorage.getItem('refresh_token'); const refresh_token = localStorage.getItem("refresh_token");
// Check if the error is due to 401 and a refresh token is available // Check if the error is due to 401 and a refresh token is available
if (error.response.status === 401 && error.response.statusText === "Unauthorized" && refresh_token !== "undefined") { if (
error.response.status === 401 &&
error.response.statusText === "Unauthorized" &&
refresh_token !== "undefined"
) {
return axiosInstance return axiosInstance
.post('/token/refresh/', { refresh: refresh_token }) .post("/token/refresh/", { refresh: refresh_token })
.then((response) => { .then(response => {
localStorage.setItem("access_token", response.data.access);
localStorage.setItem('access_token', response.data.access); axiosInstance.defaults.headers["Authorization"] = "Bearer " + response.data.access;
originalRequest.headers["Authorization"] = "Bearer " + response.data.access;
axiosInstance.defaults.headers['Authorization'] = "Bearer " + response.data.access;
originalRequest.headers['Authorization'] = "Bearer " + response.data.access;
return axiosInstance(originalRequest); return axiosInstance(originalRequest);
}) })
.catch(err => { .catch(err => {
console.log('Interceptors error: ', err); console.log("Interceptors error: ", err);
}); });
} }
return Promise.reject(error); return Promise.reject(error);
} }
); );
export default axiosInstance; export default axiosInstance;

View File

@ -1,4 +1,4 @@
import React from 'react'; import React from "react";
function EachBlog({ name, colorCode }) { function EachBlog({ name, colorCode }) {
return ( return (
@ -6,18 +6,16 @@ function EachBlog({ name, colorCode }) {
<div className={`text-xl font-bold`} style={{ color: colorCode }}> <div className={`text-xl font-bold`} style={{ color: colorCode }}>
{name} {name}
</div> </div>
<div className='h-36'> <div className="h-36">Content goes here</div>
Content goes here
</div>
</div> </div>
); );
} }
function Eisenhower() { function Eisenhower() {
return ( return (
<div className='bg-slate-100 text-left p-4 m-auto'> <div className="bg-slate-100 text-left p-4 m-auto">
<h1 className="text-3xl font-bold mb-4">The Eisenhower Matrix</h1> <h1 className="text-3xl font-bold mb-4">The Eisenhower Matrix</h1>
<div className='grid grid-rows-2 grid-cols-2 gap-2'> <div className="grid grid-rows-2 grid-cols-2 gap-2">
<EachBlog name="Urgent & Important" colorCode="#FF5733" /> <EachBlog name="Urgent & Important" colorCode="#FF5733" />
<EachBlog name="Urgent & Not important" colorCode="#FDDD5C" /> <EachBlog name="Urgent & Not important" colorCode="#FDDD5C" />
<EachBlog name="Not urgent & Important" colorCode="#189AB4" /> <EachBlog name="Not urgent & Important" colorCode="#189AB4" />

View File

@ -1,4 +1,4 @@
import React from 'react'; import React from "react";
function HomePage() { function HomePage() {
return ( return (

View File

@ -1,12 +1,12 @@
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from "react";
import { ApiUpdateUserProfile } from '../api/UserProfileApi'; import { ApiUpdateUserProfile } from "../api/UserProfileApi";
function ProfileUpdate() { function ProfileUpdate() {
const [file, setFile] = useState(null); const [file, setFile] = useState(null);
const [username, setUsername] = useState(''); const [username, setUsername] = useState("");
const [fullName, setFullName] = useState(''); const [fullName, setFullName] = useState("");
const [about, setAbout] = useState(''); const [about, setAbout] = useState("");
const defaultImage = 'https://i1.sndcdn.com/artworks-cTz48e4f1lxn5Ozp-L3hopw-t500x500.jpg'; const defaultImage = "https://i1.sndcdn.com/artworks-cTz48e4f1lxn5Ozp-L3hopw-t500x500.jpg";
const fileInputRef = useRef(null); const fileInputRef = useRef(null);
const handleImageUpload = () => { const handleImageUpload = () => {
@ -15,7 +15,7 @@ function ProfileUpdate() {
} }
}; };
const handleFileChange = (e) => { const handleFileChange = e => {
const selectedFile = e.target.files[0]; const selectedFile = e.target.files[0];
if (selectedFile) { if (selectedFile) {
setFile(selectedFile); setFile(selectedFile);
@ -24,9 +24,9 @@ function ProfileUpdate() {
const handleSave = () => { const handleSave = () => {
const formData = new FormData(); const formData = new FormData();
formData.append('profile_pic', file); formData.append("profile_pic", file);
formData.append('first_name', username); formData.append("first_name", username);
formData.append('about', about); formData.append("about", about);
ApiUpdateUserProfile(formData); ApiUpdateUserProfile(formData);
}; };
@ -45,10 +45,7 @@ function ProfileUpdate() {
ref={fileInputRef} ref={fileInputRef}
/> />
</label> </label>
<div <div className="avatar w-32 h-32 cursor-pointer hover:blur" onClick={handleImageUpload}>
className="avatar w-32 h-32 cursor-pointer hover:blur"
onClick={handleImageUpload}
>
{file ? ( {file ? (
<img src={URL.createObjectURL(file)} alt="Profile" className="rounded-full" /> <img src={URL.createObjectURL(file)} alt="Profile" className="rounded-full" />
) : ( ) : (
@ -69,7 +66,7 @@ function ProfileUpdate() {
placeholder="Enter your username" placeholder="Enter your username"
className="input w-full" className="input w-full"
value={username} value={username}
onChange={(e) => setUsername(e.target.value)} onChange={e => setUsername(e.target.value)}
/> />
</div> </div>
@ -81,7 +78,7 @@ function ProfileUpdate() {
placeholder="Enter your full name" placeholder="Enter your full name"
className="input w-full" className="input w-full"
value={fullName} value={fullName}
onChange={(e) => setFullName(e.target.value)} onChange={e => setFullName(e.target.value)}
/> />
</div> </div>
@ -92,7 +89,7 @@ function ProfileUpdate() {
placeholder="Tell us about yourself" placeholder="Tell us about yourself"
className="textarea w-full h-32" className="textarea w-full h-32"
value={about} value={about}
onChange={(e) => setAbout(e.target.value)} onChange={e => setAbout(e.target.value)}
/> />
</div> </div>

View File

@ -1,31 +1,30 @@
import React, { useState } from 'react'; import React, { useState } from "react";
import { useNavigate } from 'react-router-dom'; import { useNavigate } from "react-router-dom";
import axiosapi from '../../api/AuthenticationApi'; import axiosapi from "../../api/AuthenticationApi";
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import CssBaseline from '@mui/material/CssBaseline';
import TextField from '@mui/material/TextField';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import Link from '@mui/material/Link';
import Grid from '@mui/material/Grid';
import Box from '@mui/material/Box';
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
import Typography from '@mui/material/Typography';
import Container from '@mui/material/Container';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import Avatar from "@mui/material/Avatar";
import Button from "@mui/material/Button";
import CssBaseline from "@mui/material/CssBaseline";
import TextField from "@mui/material/TextField";
import FormControlLabel from "@mui/material/FormControlLabel";
import Checkbox from "@mui/material/Checkbox";
import Link from "@mui/material/Link";
import Grid from "@mui/material/Grid";
import Box from "@mui/material/Box";
import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
import Typography from "@mui/material/Typography";
import Container from "@mui/material/Container";
import { createTheme, ThemeProvider } from "@mui/material/styles";
function Copyright(props) { function Copyright(props) {
return ( return (
<Typography variant="body2" color="text.secondary" align="center" {...props}> <Typography variant="body2" color="text.secondary" align="center" {...props}>
{'Copyright © '} {"Copyright © "}
<Link color="inherit" href="https://github.com/TurTaskProject/TurTaskWeb"> <Link color="inherit" href="https://github.com/TurTaskProject/TurTaskWeb">
TurTask TurTask
</Link>{' '} </Link>{" "}
{new Date().getFullYear()} {new Date().getFullYear()}
{'.'} {"."}
</Typography> </Typography>
); );
} }
@ -33,18 +32,17 @@ function Copyright(props) {
const defaultTheme = createTheme(); const defaultTheme = createTheme();
export default function SignUp() { export default function SignUp() {
const Navigate = useNavigate(); const Navigate = useNavigate();
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
email: '', email: "",
username: '', username: "",
password: '', password: "",
}); });
const [error, setError] = useState(null); const [error, setError] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async (e) => { const handleSubmit = async e => {
e.preventDefault(); e.preventDefault();
setIsSubmitting(true); setIsSubmitting(true);
setError(null); setError(null);
@ -52,15 +50,15 @@ export default function SignUp() {
try { try {
axiosapi.createUser(formData); axiosapi.createUser(formData);
} catch (error) { } catch (error) {
console.error('Error creating user:', error); console.error("Error creating user:", error);
setError('Registration failed. Please try again.'); setError("Registration failed. Please try again.");
} finally { } finally {
setIsSubmitting(false); setIsSubmitting(false);
} }
Navigate('/login'); Navigate("/login");
}; };
const handleChange = (e) => { const handleChange = e => {
const { name, value } = e.target; const { name, value } = e.target;
setFormData({ ...formData, [name]: value }); setFormData({ ...formData, [name]: value });
}; };
@ -72,12 +70,11 @@ export default function SignUp() {
<Box <Box
sx={{ sx={{
marginTop: 8, marginTop: 8,
display: 'flex', display: "flex",
flexDirection: 'column', flexDirection: "column",
alignItems: 'center', alignItems: "center",
}} }}>
> <Avatar sx={{ m: 1, bgcolor: "secondary.main" }}>
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
<LockOutlinedIcon /> <LockOutlinedIcon />
</Avatar> </Avatar>
<Typography component="h1" variant="h5"> <Typography component="h1" variant="h5">
@ -127,12 +124,7 @@ export default function SignUp() {
/> />
</Grid> </Grid>
</Grid> </Grid>
<Button <Button type="submit" fullWidth variant="contained" sx={{ mt: 3, mb: 2 }}>
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
>
Sign Up Sign Up
</Button> </Button>
<Grid container justifyContent="flex-end"> <Grid container justifyContent="flex-end">

View File

@ -1,8 +1,8 @@
import axios from 'axios'; import axios from "axios";
async function refreshAccessToken() { async function refreshAccessToken() {
const refresh_token = localStorage.getItem('refresh_token'); const refresh_token = localStorage.getItem("refresh_token");
const access_token = localStorage.getItem('access_token'); const access_token = localStorage.getItem("access_token");
if (access_token) { if (access_token) {
return true; return true;
@ -12,7 +12,7 @@ async function refreshAccessToken() {
return false; return false;
} }
const refreshUrl = 'http://127.0.0.1:8000/api/token/refresh/'; const refreshUrl = "http://127.0.0.1:8000/api/token/refresh/";
try { try {
const response = await axios.post(refreshUrl, { refresh: refresh_token }); const response = await axios.post(refreshUrl, { refresh: refresh_token });
@ -22,8 +22,8 @@ async function refreshAccessToken() {
const newAccessToken = response.data.access; const newAccessToken = response.data.access;
const newRefreshToken = response.data.refresh; const newRefreshToken = response.data.refresh;
localStorage.setItem('access_token', newAccessToken); localStorage.setItem("access_token", newAccessToken);
localStorage.setItem('refresh_token', newRefreshToken); localStorage.setItem("refresh_token", newRefreshToken);
return true; return true;
} else { } else {

View File

@ -1,6 +1,6 @@
import { fetchTodoTasks } from '../../api/TaskApi'; import { fetchTodoTasks } from "../../api/TaskApi";
let eventGuid = 0 let eventGuid = 0;
// function getDateAndTime(dateString) { // function getDateAndTime(dateString) {
// const dateObject = new Date(dateString); // const dateObject = new Date(dateString);
@ -18,14 +18,14 @@ let eventGuid = 0
// return dateFormatted + timeFormatted; // return dateFormatted + timeFormatted;
// } // }
const mapResponseToEvents = (response) => { const mapResponseToEvents = response => {
return response.map(item => ({ return response.map(item => ({
id: createEventId(), id: createEventId(),
title: item.title, title: item.title,
start: item.start_event, start: item.start_event,
end: item.end_event, end: item.end_event,
})); }));
} };
export async function getEvents() { export async function getEvents() {
try { try {

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React, { useState } from "react";
import { formatDate } from "@fullcalendar/core"; import { formatDate } from "@fullcalendar/core";
import FullCalendar from "@fullcalendar/react"; import FullCalendar from "@fullcalendar/react";
import dayGridPlugin from "@fullcalendar/daygrid"; import dayGridPlugin from "@fullcalendar/daygrid";
@ -79,7 +79,7 @@ export default class Calendar extends React.Component {
}); });
}; };
handleDateSelect = (selectInfo) => { handleDateSelect = selectInfo => {
let title = prompt("Please enter a new title for your event"); let title = prompt("Please enter a new title for your event");
let calendarApi = selectInfo.view.calendar; let calendarApi = selectInfo.view.calendar;
@ -96,13 +96,13 @@ export default class Calendar extends React.Component {
} }
}; };
handleEventClick = (clickInfo) => { handleEventClick = clickInfo => {
if (confirm(`Are you sure you want to delete the event '${clickInfo.event.title}'`)) { if (confirm(`Are you sure you want to delete the event '${clickInfo.event.title}'`)) {
clickInfo.event.remove(); clickInfo.event.remove();
} }
}; };
handleEvents = (events) => { handleEvents = events => {
this.setState({ this.setState({
currentEvents: events, currentEvents: events,
}); });

View File

@ -1,4 +1,4 @@
import React from 'react'; import React from "react";
function PlusIcon() { function PlusIcon() {
return ( return (
@ -8,13 +8,8 @@ function PlusIcon() {
viewBox="0 0 24 24" viewBox="0 0 24 24"
strokeWidth={1.5} strokeWidth={1.5}
stroke="currentColor" stroke="currentColor"
className="w-6 h-6" className="w-6 h-6">
> <path strokeLinecap="round" strokeLinejoin="round" d="M12 9v6m3-3H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" />
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M12 9v6m3-3H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg> </svg>
); );
} }

View File

@ -1,22 +1,20 @@
import React from 'react'; import React from "react";
function TrashIcon() { function TrashIcon() {
return ( return React.createElement(
React.createElement(
"svg", "svg",
{ {
xmlns: "http://www.w3.org/2000/svg", xmlns: "http://www.w3.org/2000/svg",
fill: "none", fill: "none",
viewBox: "0 0 24 24", viewBox: "0 0 24 24",
strokeWidth: 1.5, strokeWidth: 1.5,
className: "w-6 h-6" className: "w-6 h-6",
}, },
React.createElement("path", { React.createElement("path", {
strokeLinecap: "round", strokeLinecap: "round",
strokeLinejoin: "round", strokeLinejoin: "round",
d: "M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" d: "M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0",
}) })
)
); );
} }

View File

@ -5,29 +5,14 @@ import { useMemo, useState } from "react";
import PlusIcon from "../icons/plusIcon"; import PlusIcon from "../icons/plusIcon";
import TaskCard from "./taskCard"; import TaskCard from "./taskCard";
function ColumnContainer({ function ColumnContainer({ column, deleteColumn, updateColumn, createTask, tasks, deleteTask, updateTask }) {
column,
deleteColumn,
updateColumn,
createTask,
tasks,
deleteTask,
updateTask,
}) {
const [editMode, setEditMode] = useState(false); const [editMode, setEditMode] = useState(false);
const tasksIds = useMemo(() => { const tasksIds = useMemo(() => {
return tasks.map((task) => task.id); return tasks.map(task => task.id);
}, [tasks]); }, [tasks]);
const { const { setNodeRef, attributes, listeners, transform, transition, isDragging } = useSortable({
setNodeRef,
attributes,
listeners,
transform,
transition,
isDragging,
} = useSortable({
id: column.id, id: column.id,
data: { data: {
type: "Column", type: "Column",
@ -57,8 +42,7 @@ function ColumnContainer({
rounded-md rounded-md
flex flex
flex-col flex-col
" "></div>
></div>
); );
} }
@ -74,8 +58,7 @@ function ColumnContainer({
rounded-md rounded-md
flex flex
flex-col flex-col
" ">
>
{/* Column title */} {/* Column title */}
<div <div
{...attributes} {...attributes}
@ -97,8 +80,7 @@ function ColumnContainer({
flex flex
items-center items-center
justify-between justify-between
" ">
>
<div className="flex gap-2"> <div className="flex gap-2">
<div <div
className=" className="
@ -110,8 +92,7 @@ function ColumnContainer({
py-1 py-1
text-sm text-sm
rounded-full rounded-full
" ">
>
0 0
</div> </div>
{!editMode && column.title} {!editMode && column.title}
@ -119,12 +100,12 @@ function ColumnContainer({
<input <input
className="bg-black focus:border-rose-500 border rounded outline-none px-2" className="bg-black focus:border-rose-500 border rounded outline-none px-2"
value={column.title} value={column.title}
onChange={(e) => updateColumn(column.id, e.target.value)} onChange={e => updateColumn(column.id, e.target.value)}
autoFocus autoFocus
onBlur={() => { onBlur={() => {
setEditMode(false); setEditMode(false);
}} }}
onKeyDown={(e) => { onKeyDown={e => {
if (e.key !== "Enter") return; if (e.key !== "Enter") return;
setEditMode(false); setEditMode(false);
}} }}
@ -142,8 +123,7 @@ function ColumnContainer({
rounded rounded
px-1 px-1
py-2 py-2
" ">
>
<TrashIcon /> <TrashIcon />
</button> </button>
</div> </div>
@ -151,13 +131,8 @@ function ColumnContainer({
{/* Column task container */} {/* Column task container */}
<div className="flex flex-grow flex-col gap-4 p-2 overflow-x-hidden overflow-y-auto"> <div className="flex flex-grow flex-col gap-4 p-2 overflow-x-hidden overflow-y-auto">
<SortableContext items={tasksIds}> <SortableContext items={tasksIds}>
{tasks.map((task) => ( {tasks.map(task => (
<TaskCard <TaskCard key={task.id} task={task} deleteTask={deleteTask} updateTask={updateTask} />
key={task.id}
task={task}
deleteTask={deleteTask}
updateTask={updateTask}
/>
))} ))}
</SortableContext> </SortableContext>
</div> </div>
@ -166,8 +141,7 @@ function ColumnContainer({
className="flex gap-2 items-center border-columnBackgroundColor border-2 rounded-md p-4 border-x-columnBackgroundColor hover:bg-mainBackgroundColor hover:text-rose-500 active:bg-black" className="flex gap-2 items-center border-columnBackgroundColor border-2 rounded-md p-4 border-x-columnBackgroundColor hover:bg-mainBackgroundColor hover:text-rose-500 active:bg-black"
onClick={() => { onClick={() => {
createTask(column.id); createTask(column.id);
}} }}>
>
<PlusIcon /> <PlusIcon />
Add task Add task
</button> </button>

View File

@ -1,13 +1,7 @@
import PlusIcon from "../icons/plusIcon" import PlusIcon from "../icons/plusIcon";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import ColumnContainer from "./columnContainer"; import ColumnContainer from "./columnContainer";
import { import { DndContext, DragOverlay, PointerSensor, useSensor, useSensors } from "@dnd-kit/core";
DndContext,
DragOverlay,
PointerSensor,
useSensor,
useSensors,
} from "@dnd-kit/core";
import { SortableContext, arrayMove } from "@dnd-kit/sortable"; import { SortableContext, arrayMove } from "@dnd-kit/sortable";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import TaskCard from "./taskCard"; import TaskCard from "./taskCard";
@ -98,7 +92,7 @@ const defaultTasks = [
function KanbanBoard() { function KanbanBoard() {
const [columns, setColumns] = useState(defaultCols); const [columns, setColumns] = useState(defaultCols);
const columnsId = useMemo(() => columns.map((col) => col.id), [columns]); const columnsId = useMemo(() => columns.map(col => col.id), [columns]);
const [tasks, setTasks] = useState(defaultTasks); const [tasks, setTasks] = useState(defaultTasks);
@ -123,18 +117,12 @@ function KanbanBoard() {
items-center items-center
overflow-x-auto overflow-x-auto
overflow-y-hidden overflow-y-hidden
" ">
> <DndContext sensors={sensors} onDragStart={onDragStart} onDragEnd={onDragEnd} onDragOver={onDragOver}>
<DndContext
sensors={sensors}
onDragStart={onDragStart}
onDragEnd={onDragEnd}
onDragOver={onDragOver}
>
<div className="m-auto flex gap-4"> <div className="m-auto flex gap-4">
<div className="flex gap-4"> <div className="flex gap-4">
<SortableContext items={columnsId}> <SortableContext items={columnsId}>
{columns.map((col) => ( {columns.map(col => (
<ColumnContainer <ColumnContainer
key={col.id} key={col.id}
column={col} column={col}
@ -143,7 +131,7 @@ function KanbanBoard() {
createTask={createTask} createTask={createTask}
deleteTask={deleteTask} deleteTask={deleteTask}
updateTask={updateTask} updateTask={updateTask}
tasks={tasks.filter((task) => task.columnId === col.id)} tasks={tasks.filter(task => task.columnId === col.id)}
/> />
))} ))}
</SortableContext> </SortableContext>
@ -166,8 +154,7 @@ function KanbanBoard() {
hover:ring-2 hover:ring-2
flex flex
gap-2 gap-2
" ">
>
<PlusIcon /> <PlusIcon />
Add Column Add Column
</button> </button>
@ -183,18 +170,10 @@ function KanbanBoard() {
createTask={createTask} createTask={createTask}
deleteTask={deleteTask} deleteTask={deleteTask}
updateTask={updateTask} updateTask={updateTask}
tasks={tasks.filter( tasks={tasks.filter(task => task.columnId === activeColumn.id)}
(task) => task.columnId === activeColumn.id
)}
/>
)}
{activeTask && (
<TaskCard
task={activeTask}
deleteTask={deleteTask}
updateTask={updateTask}
/> />
)} )}
{activeTask && <TaskCard task={activeTask} deleteTask={deleteTask} updateTask={updateTask} />}
</DragOverlay>, </DragOverlay>,
document.body document.body
)} )}
@ -213,12 +192,12 @@ function KanbanBoard() {
} }
function deleteTask(id) { function deleteTask(id) {
const newTasks = tasks.filter((task) => task.id !== id); const newTasks = tasks.filter(task => task.id !== id);
setTasks(newTasks); setTasks(newTasks);
} }
function updateTask(id, content) { function updateTask(id, content) {
const newTasks = tasks.map((task) => { const newTasks = tasks.map(task => {
if (task.id !== id) return task; if (task.id !== id) return task;
return { ...task, content }; return { ...task, content };
}); });
@ -236,15 +215,15 @@ function KanbanBoard() {
} }
function deleteColumn(id) { function deleteColumn(id) {
const filteredColumns = columns.filter((col) => col.id !== id); const filteredColumns = columns.filter(col => col.id !== id);
setColumns(filteredColumns); setColumns(filteredColumns);
const newTasks = tasks.filter((t) => t.columnId !== id); const newTasks = tasks.filter(t => t.columnId !== id);
setTasks(newTasks); setTasks(newTasks);
} }
function updateColumn(id, title) { function updateColumn(id, title) {
const newColumns = columns.map((col) => { const newColumns = columns.map(col => {
if (col.id !== id) return col; if (col.id !== id) return col;
return { ...col, title }; return { ...col, title };
}); });
@ -279,10 +258,10 @@ function KanbanBoard() {
const isActiveAColumn = active.data.current?.type === "Column"; const isActiveAColumn = active.data.current?.type === "Column";
if (!isActiveAColumn) return; if (!isActiveAColumn) return;
setColumns((columns) => { setColumns(columns => {
const activeColumnIndex = columns.findIndex((col) => col.id === activeId); const activeColumnIndex = columns.findIndex(col => col.id === activeId);
const overColumnIndex = columns.findIndex((col) => col.id === overId); const overColumnIndex = columns.findIndex(col => col.id === overId);
return arrayMove(columns, activeColumnIndex, overColumnIndex); return arrayMove(columns, activeColumnIndex, overColumnIndex);
}); });
@ -303,9 +282,9 @@ function KanbanBoard() {
if (!isActiveATask) return; if (!isActiveATask) return;
if (isActiveATask && isOverATask) { if (isActiveATask && isOverATask) {
setTasks((tasks) => { setTasks(tasks => {
const activeIndex = tasks.findIndex((t) => t.id === activeId); const activeIndex = tasks.findIndex(t => t.id === activeId);
const overIndex = tasks.findIndex((t) => t.id === overId); const overIndex = tasks.findIndex(t => t.id === overId);
if (tasks[activeIndex].columnId !== tasks[overIndex].columnId) { if (tasks[activeIndex].columnId !== tasks[overIndex].columnId) {
tasks[activeIndex].columnId = tasks[overIndex].columnId; tasks[activeIndex].columnId = tasks[overIndex].columnId;
@ -319,8 +298,8 @@ function KanbanBoard() {
const isOverAColumn = over.data.current?.type === "Column"; const isOverAColumn = over.data.current?.type === "Column";
if (isActiveATask && isOverAColumn) { if (isActiveATask && isOverAColumn) {
setTasks((tasks) => { setTasks(tasks => {
const activeIndex = tasks.findIndex((t) => t.id === activeId); const activeIndex = tasks.findIndex(t => t.id === activeId);
tasks[activeIndex].columnId = overId; tasks[activeIndex].columnId = overId;
return arrayMove(tasks, activeIndex, activeIndex); return arrayMove(tasks, activeIndex, activeIndex);

View File

@ -7,14 +7,7 @@ function TaskCard({ task, deleteTask, updateTask }) {
const [mouseIsOver, setMouseIsOver] = useState(false); const [mouseIsOver, setMouseIsOver] = useState(false);
const [editMode, setEditMode] = useState(true); const [editMode, setEditMode] = useState(true);
const { const { setNodeRef, attributes, listeners, transform, transition, isDragging } = useSortable({
setNodeRef,
attributes,
listeners,
transform,
transition,
isDragging,
} = useSortable({
id: task.id, id: task.id,
data: { data: {
type: "Task", type: "Task",
@ -29,7 +22,7 @@ function TaskCard({ task, deleteTask, updateTask }) {
}; };
const toggleEditMode = () => { const toggleEditMode = () => {
setEditMode((prev) => !prev); setEditMode(prev => !prev);
setMouseIsOver(false); setMouseIsOver(false);
}; };
@ -53,8 +46,7 @@ function TaskCard({ task, deleteTask, updateTask }) {
style={style} style={style}
{...attributes} {...attributes}
{...listeners} {...listeners}
className="bg-mainBackgroundColor p-2.5 h-[100px] min-h-[100px] items-center flex text-left rounded-xl hover:ring-2 hover:ring-inset hover:ring-rose-500 cursor-grab relative" className="bg-mainBackgroundColor p-2.5 h-[100px] min-h-[100px] items-center flex text-left rounded-xl hover:ring-2 hover:ring-inset hover:ring-rose-500 cursor-grab relative">
>
<textarea <textarea
className=" className="
h-[90%] h-[90%]
@ -64,12 +56,12 @@ function TaskCard({ task, deleteTask, updateTask }) {
autoFocus autoFocus
placeholder="Task content here" placeholder="Task content here"
onBlur={toggleEditMode} onBlur={toggleEditMode}
onKeyDown={(e) => { onKeyDown={e => {
if (e.key === "Enter" && e.shiftKey) { if (e.key === "Enter" && e.shiftKey) {
toggleEditMode(); toggleEditMode();
} }
}} }}
onChange={(e) => updateTask(task.id, e.target.value)} onChange={e => updateTask(task.id, e.target.value)}
/> />
</div> </div>
); );
@ -88,19 +80,15 @@ function TaskCard({ task, deleteTask, updateTask }) {
}} }}
onMouseLeave={() => { onMouseLeave={() => {
setMouseIsOver(false); setMouseIsOver(false);
}} }}>
> <p className="my-auto h-[90%] w-full overflow-y-auto overflow-x-hidden whitespace-pre-wrap">{task.content}</p>
<p className="my-auto h-[90%] w-full overflow-y-auto overflow-x-hidden whitespace-pre-wrap">
{task.content}
</p>
{mouseIsOver && ( {mouseIsOver && (
<button <button
onClick={() => { onClick={() => {
deleteTask(task.id); deleteTask(task.id);
}} }}
className="stroke-white absolute right-4 top-1/2 -translate-y-1/2 bg-columnBackgroundColor p-2 rounded opacity-60 hover:opacity-100" className="stroke-white absolute right-4 top-1/2 -translate-y-1/2 bg-columnBackgroundColor p-2 rounded opacity-60 hover:opacity-100">
>
<TrashIcon /> <TrashIcon />
</button> </button>
)} )}

View File

@ -4,8 +4,8 @@ import IsAuthenticated from "../../hooks/authentication/IsAuthenticated";
import axiosapi from "../../api/AuthenticationApi"; import axiosapi from "../../api/AuthenticationApi";
const settings = { const settings = {
Profile: '/update_profile', Profile: "/update_profile",
Account: '/account', Account: "/account",
}; };
function NavBar() { function NavBar() {

View File

@ -1,26 +1,26 @@
import React, { useState } from 'react'; import React, { useState } from "react";
import axiosapi from '../api/axiosapi'; import axiosapi from "../api/axiosapi";
import TextField from '@material-ui/core/TextField'; import TextField from "@material-ui/core/TextField";
import Typography from '@material-ui/core/Typography'; import Typography from "@material-ui/core/Typography";
import CssBaseline from '@material-ui/core/CssBaseline'; import CssBaseline from "@material-ui/core/CssBaseline";
import Container from '@material-ui/core/Container'; import Container from "@material-ui/core/Container";
import Button from '@material-ui/core/Button'; import Button from "@material-ui/core/Button";
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from "@material-ui/core/styles";
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles(theme => ({
// Styles for various elements // Styles for various elements
paper: { paper: {
marginTop: theme.spacing(8), marginTop: theme.spacing(8),
display: 'flex', display: "flex",
flexDirection: 'column', flexDirection: "column",
alignItems: 'center', alignItems: "center",
}, },
avatar: { avatar: {
margin: theme.spacing(1), margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main, backgroundColor: theme.palette.secondary.main,
}, },
form: { form: {
width: '100%', width: "100%",
marginTop: theme.spacing(1), marginTop: theme.spacing(1),
}, },
submit: { submit: {
@ -31,14 +31,14 @@ const useStyles = makeStyles((theme) => ({
const Signup = () => { const Signup = () => {
const classes = useStyles(); const classes = useStyles();
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
email: '', email: "",
username: '', username: "",
password: '', password: "",
}); });
const [error, setError] = useState(null); const [error, setError] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async (e) => { const handleSubmit = async e => {
e.preventDefault(); e.preventDefault();
setIsSubmitting(true); setIsSubmitting(true);
setError(null); setError(null);
@ -46,14 +46,14 @@ const Signup = () => {
try { try {
axiosapi.createUser(formData); axiosapi.createUser(formData);
} catch (error) { } catch (error) {
console.error('Error creating user:', error); console.error("Error creating user:", error);
setError('Registration failed. Please try again.'); // Set an error message setError("Registration failed. Please try again."); // Set an error message
} finally { } finally {
setIsSubmitting(false); setIsSubmitting(false);
} }
}; };
const handleChange = (e) => { const handleChange = e => {
const { name, value } = e.target; const { name, value } = e.target;
setFormData({ ...formData, [name]: value }); setFormData({ ...formData, [name]: value });
}; };
@ -102,9 +102,8 @@ const Signup = () => {
variant="contained" variant="contained"
color="primary" color="primary"
className={classes.submit} className={classes.submit}
disabled={isSubmitting} disabled={isSubmitting}>
> {isSubmitting ? "Signing up..." : "Sign Up"}
{isSubmitting ? 'Signing up...' : 'Sign Up'}
</Button> </Button>
</form> </form>
{error && <Typography color="error">{error}</Typography>} {error && <Typography color="error">{error}</Typography>}

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from "react";
import axiosapi from '../api/AuthenticationApi'; import axiosapi from "../api/AuthenticationApi";
import { Button } from '@mui/material'; import { Button } from "@mui/material";
import { useNavigate } from 'react-router-dom'; import { useNavigate } from "react-router-dom";
function TestAuth() { function TestAuth() {
let Navigate = useNavigate(); let Navigate = useNavigate();
@ -10,10 +10,13 @@ function TestAuth() {
useEffect(() => { useEffect(() => {
// Fetch the "hello" data from the server when the component mounts // Fetch the "hello" data from the server when the component mounts
axiosapi.getGreeting().then(res => { axiosapi
.getGreeting()
.then(res => {
console.log(res.data); console.log(res.data);
setMessage(res.data.user); setMessage(res.data.user);
}).catch(err => { })
.catch(err => {
console.log(err); console.log(err);
setMessage(""); setMessage("");
}); });
@ -22,8 +25,8 @@ function TestAuth() {
const logout = () => { const logout = () => {
// Log out the user, clear tokens, and navigate to the "/testAuth" route // Log out the user, clear tokens, and navigate to the "/testAuth" route
axiosapi.apiUserLogout(); axiosapi.apiUserLogout();
Navigate('/testAuth'); Navigate("/testAuth");
} };
return ( return (
<div> <div>
@ -31,7 +34,9 @@ function TestAuth() {
<div> <div>
<h1 class="text-xl font-bold">Login! Hello!</h1> <h1 class="text-xl font-bold">Login! Hello!</h1>
<h2>{message}</h2> <h2>{message}</h2>
<Button variant="contained" onClick={logout}>Logout</Button> <Button variant="contained" onClick={logout}>
Logout
</Button>
</div> </div>
)} )}
{message === "" && <h1 class="text-xl font-bold">Need to sign in, No authentication found</h1>} {message === "" && <h1 class="text-xl font-bold">Need to sign in, No authentication found</h1>}

View File

@ -1,21 +1,21 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from "react";
function IsAuthenticated() { function IsAuthenticated() {
const [isAuthenticated, setIsAuthenticated] = useState(() => { const [isAuthenticated, setIsAuthenticated] = useState(() => {
const access_token = localStorage.getItem('access_token'); const access_token = localStorage.getItem("access_token");
return !!access_token; return !!access_token;
}); });
useEffect(() => { useEffect(() => {
const handleTokenChange = () => { const handleTokenChange = () => {
const newAccessToken = localStorage.getItem('access_token'); const newAccessToken = localStorage.getItem("access_token");
setIsAuthenticated(!!newAccessToken); setIsAuthenticated(!!newAccessToken);
}; };
window.addEventListener('storage', handleTokenChange); window.addEventListener("storage", handleTokenChange);
return () => { return () => {
window.removeEventListener('storage', handleTokenChange); window.removeEventListener("storage", handleTokenChange);
}; };
}, []); }, []);

View File

@ -8,16 +8,14 @@
body { body {
margin: 0; margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', "Droid Sans", "Helvetica Neue", sans-serif;
sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
code { code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
monospace;
} }
.nav-link { .nav-link {