Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

William Z. tech test #12

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,32 @@ Send us the project and answer to those simple questions :
- Which feature did you develop and why ?
- Do you have any feedback about the code / architecture of the project and what was the difficulty you encountered while doing it ?



## Solved bugs
# Can't access to Projects
When you click on a project name, you will have an error screen. I can't find the project name (undefined project.name).
To fix this problem, we have to wait the result of the async method, during this time we let a loader.

# Can't update User information
When you add new informations to user and click on update. Toast message said that's update. But when you comeback to user informations, that's not the case.
To fix this problem, I change the behavior or the button

# Can't connect to new user created by UI
When you create a new user with the UI. User is created. Then, you logged out and try to log with the new user created. You can't log in because User is not know in the console log.
I found that user and password are set in lower case. So this lead to create a "false" account. I simply remove this function to not alterate the authentification process.

# Reduce query and display user name
When you display a project, the request start to retrieve all projects from the database but you only need one result because project name are unique.
When you create a user, and list all users, name of users are not displayed.
I have noticed that model from database and attributes are not correctly set for user (username != name).


## New feature
I add a small dashboard that count number of projects, of users, and activities. Add a feed of users from the input activity next time.

## Feedback about the code / architecture of the project and difficulties
The code at some point is understable if you master the React framework, and in some file it is completly unreadable.
The non-typed language doesn't help at all and so the debugging too.

The code is well structured. I clearly have some facility to navigate and understand how responsability is shared.
2 changes: 1 addition & 1 deletion api/src/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class Auth {

async signin(req, res) {
let { password, username } = req.body;
username = (username || "").trim().toLowerCase();
username = (username || "").trim();

if (!username || !password) return res.status(400).send({ ok: false, code: EMAIL_AND_PASSWORD_REQUIRED });

Expand Down
2 changes: 1 addition & 1 deletion api/src/controllers/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ router.get("/list", passport.authenticate("user", { session: false }), async (re

router.get("/:id", passport.authenticate("user", { session: false }), async (req, res) => {
try {
const data = await ProjectObject.find({ _id: req.params.id });
const data = await ProjectObject.findOne({ _id: req.params.id });
return res.status(200).send({ ok: true, data });
} catch (error) {
console.log(error);
Expand Down
55 changes: 55 additions & 0 deletions app/src/components/dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React, { useEffect, useState } from "react";
import api from "../services/api";
import Loader from "./loader";

const Dashboard = () => {
const [loading, setLoading] = useState(true);
const [data, setData] = useState({
totalUsers: 0,
totalProjects: 0,
totalActivities: 0,
});

useEffect(() => {
const fetchData = async () => {
try {
const [usersRes, projectsRes, activitiesRes] = await Promise.all([api.get("/user"), api.get("/project"), api.get("/activity")]);

setData({
totalUsers: usersRes.data.length,
totalProjects: projectsRes.data.length,
totalActivities: activitiesRes.data.length,
});
} catch (error) {
console.error("Failed to fetch dashboard data", error);
} finally {
setLoading(false);
}
};

fetchData();
}, []);

if (loading) {
return <Loader />;
}

return (
<div className="dashboard">
<div className="stat">
<h3>Total Users</h3>
<p>{data.totalUsers}</p>
</div>
<div className="stat">
<h3>Total Projects</h3>
<p>{data.totalProjects}</p>
</div>
<div className="stat">
<h3>Total Activities</h3>
<p>{data.totalActivities}</p>
</div>
</div>
);
};

export default Dashboard;
13 changes: 13 additions & 0 deletions app/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,16 @@ table td {
border-radius: 10px;
border: 3px solid #ffffff;
}

.dashboard {
display: flex;
gap: 20px;
margin-bottom: 20px;
}

.stat {
background: #f0f0f0;
padding: 20px;
border-radius: 10px;
text-align: center;
}
34 changes: 20 additions & 14 deletions app/src/scenes/home/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useEffect, useState } from "react";
import api from "../../services/api";
import Dashboard from "../../components/dashboard";

const Home = () => {
const [availableUsers, setAvailableUsers] = useState();
Expand All @@ -13,21 +14,26 @@ const Home = () => {
}, []);

return (
<div className="px-2 md:!px-8 flex flex-col md:flex-row gap-5 mt-5">
<div className="flex-1 mb-[10px]">
<h2 className="text-[22px] font-semibold mb-4">Available</h2>
{availableUsers?.map((user) => (
<div key={user._id} className="bg-white mb-[10px] rounded-lg shadow-sm flex gap-4 p-3">
<img src={user.avatar} alt="userlogo" className="rounded-full w-14 h-14" />
<div>
<h3 className="font-semibold text-lg mb-[3px]">{user.name}</h3>
{/* <h3 className="text-[#676D7C] text-sm">{user.email}</h3> */}
<h3 className="text-[#676D7C] text-sm">{user.job_title}</h3>
<p className="text-[#676D7C] text-sm capitalize">{user.availability}</p>
<div>
<div className="px-2 md:!px-8 flex flex-col md:flex-row gap-5 mt-5">
<div className="flex-1 mb-[10px]">
<h2 className="text-[22px] font-semibold mb-4">Available</h2>
{availableUsers?.map((user) => (
<div key={user._id} className="bg-white mb-[10px] rounded-lg shadow-sm flex gap-4 p-3">
<img src={user.avatar} alt="userlogo" className="rounded-full w-14 h-14" />
<div>
<h3 className="font-semibold text-lg mb-[3px]">{user.name}</h3>
{/* <h3 className="text-[#676D7C] text-sm">{user.email}</h3> */}
<h3 className="text-[#676D7C] text-sm">{user.job_title}</h3>
<p className="text-[#676D7C] text-sm capitalize">{user.availability}</p>
</div>
</div>
</div>
))}
{availableUsers?.length === 0 ? <span className="italic text-gray-600">No available users.</span> : null}
))}
{availableUsers?.length === 0 ? <span className="italic text-gray-600">No available users.</span> : null}
</div>
</div>
<div className="bg-white mb-[10px] rounded-lg shadow-sm flex gap-4 p-3">
<Dashboard />
</div>
</div>
);
Expand Down
5 changes: 4 additions & 1 deletion app/src/scenes/project/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ export default function ProjectView() {
}

const ProjectDetails = ({ project }) => {
if(!project) return <Loader />
else{
console.log(project);
return (
<div>
Expand All @@ -70,7 +72,7 @@ const ProjectDetails = ({ project }) => {
<div className="flex justify-between gap-2">
<div className="flex gap-20">
<span className="w-fit text-[20px] text-[#0C1024] font-bold">Nom du projet : </span>
<span className="w-fit text-[20px] text-[#0C1024] font-bold">{project.name.toString()}</span>
<span className="w-fit text-[20px] text-[#0C1024] font-bold">{project.name ? project.name : ""}</span>
</div>
<div className="flex flex-1 flex-column items-end gap-3">
<Links project={project} />
Expand Down Expand Up @@ -98,6 +100,7 @@ const ProjectDetails = ({ project }) => {
</div>
);
};
}
const Budget = ({ project }) => {
const [activities, setActivities] = useState([10, 29, 18, 12]);

Expand Down
4 changes: 2 additions & 2 deletions app/src/scenes/user/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ const Create = () => {
<div className="flex justify-between flex-wrap">
<div className="w-full md:w-[48%] mt-2">
<div className="text-[14px] text-[#212325] font-medium ">Name</div>
<input className="projectsInput text-[14px] font-normal text-[#212325] rounded-[10px]" name="username" value={values.username} onChange={handleChange} />
<input className="projectsInput text-[14px] font-normal text-[#212325] rounded-[10px]" name="name" value={values.name} onChange={handleChange} />
</div>
<div className="w-full md:w-[48%] mt-2">
<div className="text-[14px] text-[#212325] font-medium ">Email</div>
Expand All @@ -139,7 +139,7 @@ const Create = () => {
{/* Password */}
<div className="w-full md:w-[48%] mt-2">
<div className="text-[14px] text-[#212325] font-medium ">Password</div>
<input className="projectsInput text-[14px] font-normal text-[#212325] rounded-[10px]" name="password" value={values.password} onChange={handleChange} />
<input className="projectsInput text-[14px] font-normal text-[#212325] rounded-[10px]" type="password" name="password" value={values.password} onChange={handleChange} />
</div>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions app/src/scenes/user/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ const Detail = ({ user }) => {
</div>

<div className="flex mt-2">
<LoadingButton className="bg-[#0560FD] text-[16px] font-medium text-[#FFFFFF] py-[12px] px-[22px] rounded-[10px]" loading={isSubmitting} onChange={handleSubmit}>
<button className="bg-[#0560FD] text-[16px] font-medium text-[#FFFFFF] py-[12px] px-[22px] rounded-[10px]" loading={isSubmitting} onClick={handleSubmit}>
Update
</LoadingButton>
</button>
<button className="ml-[10px] bg-[#F43F5E] text-[16px] font-medium text-[#FFFFFF] py-[12px] px-[22px] rounded-[10px]" onClick={deleteData}>
Delete
</button>
Expand Down