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

feat: Update profile #254

Merged
merged 2 commits into from
Jan 17, 2024
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ dist-ssr

# Test data
e2e/laboratories/data/java-downloaded.zip
e2e/laboratories/data/Test block name.zip
34 changes: 34 additions & 0 deletions e2e/register/RegisterAdmins.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,38 @@ test.describe.serial("Admin registration", () => {
await logout.click();
await page.waitForURL(/\/login$/);
});

test("Admins can update their profile", async ({ page }) => {
// Logout from the current admin account
const logout = page.getByRole("link", { name: "Logout", exact: true });
await expect(logout).toBeVisible();
await logout.click();
await page.waitForURL(/\/login$/);

// Login as the new admin
await page.goto("/login");
await page.getByLabel("Email").fill(newAdminEmail);
await page.getByLabel("Password").fill(getDefaultPassword());
await page.getByRole("button", { name: "Submit" }).click();

await page.waitForURL(/\/admins$/);

// Navigate to the profile view
await page.getByRole("link", { name: "Profile", exact: true }).click();
await page.waitForURL(/\/profile$/);

// Update the profile
const newName = getRandomName();
const newEmail = getRandomEmail();

await page.getByLabel("Full name").fill(newName);
await page.getByLabel("Email").fill(newEmail);
await page.getByLabel("Password confirmation").fill(getDefaultPassword());
await page.getByRole("button", { name: "Update" }).click();

// Assert the alert is shown
await expect(
page.getByText("Your profile has been updated successfully")
).toBeVisible();
});
});
29 changes: 29 additions & 0 deletions e2e/register/RegisterStudents.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,33 @@ test.describe.serial("Student registration", () => {
await page.getByRole("link", { name: "Logout", exact: true }).click();
await page.waitForURL(/\/login$/);
});

test("Student can update their profile", async ({ page }) => {
await page.goto("/login");
await page.getByLabel("Email").fill(newStudentEmail);
await page.getByLabel("Password").fill(getDefaultPassword());
await page.getByRole("button", { name: "Submit" }).click();

await page.waitForURL(/\/courses$/);

// Navigate to the profile view
await page.getByRole("link", { name: "Profile", exact: true }).click();
await page.waitForURL(/\/profile$/);

// Update the profile
const newName = getRandomName();
const newEmail = getRandomEmail();
const newID = getRandomUniversityID();

await page.getByLabel("Full name").fill(newName);
await page.getByLabel("Email").fill(newEmail);
await page.getByLabel("Institutional ID").fill(newID);
await page.getByLabel("Password confirmation").fill(getDefaultPassword());
await page.getByRole("button", { name: "Update" }).click();

// Assert the alert is shown
await expect(
page.getByText("Your profile has been updated successfully")
).toBeVisible();
});
});
34 changes: 34 additions & 0 deletions e2e/register/RegisterTeachers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,38 @@ test.describe.serial("Teacher registration", () => {
await logout.click();
await page.waitForURL(/\/login$/);
});

test("Teachers can update their profile", async ({ page }) => {
// Logout from the admin account
const logout = page.getByRole("link", { name: "Logout", exact: true });
await expect(logout).toBeVisible();
await logout.click();
await page.waitForURL(/\/login$/);

// Login as a teacher
await page.goto("/login");
await page.getByLabel("Email").fill(newTeacherEmail);
await page.getByLabel("Password").fill(getDefaultPassword());
await page.getByRole("button", { name: "Submit" }).click();

await page.waitForURL(/\/courses$/);

// Navigate to the profile view
await page.getByRole("link", { name: "Profile", exact: true }).click();
await page.waitForURL(/\/profile$/);

// Update the profile
const newName = getRandomName();
const newEmail = getRandomEmail();

await page.getByLabel("Full name").fill(newName);
await page.getByLabel("Email").fill(newEmail);
await page.getByLabel("Password confirmation").fill(getDefaultPassword());
await page.getByRole("button", { name: "Update" }).click();

// Assert the alert is shown
await expect(
page.getByText("Your profile has been updated successfully")
).toBeVisible();
});
});
9 changes: 9 additions & 0 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { CourseParticipants } from "@/screens/course-page/participants/CoursePar
import { CoursesHome } from "@/screens/courses-list/CoursesHome";
import { EditLaboratory } from "@/screens/edit-laboratory/EditLaboratory";
import { EditRubricView } from "@/screens/edit-rubric/EditRubricView";
import { ProfileView } from "@/screens/profile/ProfileView";
import { RubricsHome } from "@/screens/rubrics-list/RubricsHome";
import { FormContainer } from "@/screens/session/FormContainer";
import { Login } from "@/screens/session/login/Login";
Expand Down Expand Up @@ -88,6 +89,14 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
</AuthMiddleware>
}
/>
<Route
path="/profile"
element={
<AuthMiddleware mustBeLoggedIn>
<ProfileView />
</AuthMiddleware>
}
/>
<Route
path="/admins"
element={
Expand Down
28 changes: 28 additions & 0 deletions src/screens/profile/ProfileView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";

import { UpdateProfile } from "./components/UpdateProfile";

export const ProfileView = () => {
return (
<div className="px-4">
<main className="mx-auto my-4 max-w-md rounded-md border p-4">
<Tabs defaultValue="update-profile">
<TabsList className="w-full">
<TabsTrigger className="flex-grow" value="update-profile">
Update profile
</TabsTrigger>
<TabsTrigger className="flex-grow" value="update-password">
Update password
</TabsTrigger>
</TabsList>
<TabsContent value="update-profile">
<UpdateProfile />
</TabsContent>
<TabsContent value="update-password">
<p>Password</p>
</TabsContent>
</Tabs>
</main>
</div>
);
};
56 changes: 56 additions & 0 deletions src/screens/profile/components/UpdateProfile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { CustomError } from "@/components/CustomError";
import { getUserProfileService } from "@/services/accounts/get-user-profile.service";
import { useQuery } from "@tanstack/react-query";
import { toast } from "sonner";

import { UpdateProfileSkeleton } from "../skeletons/UpdateProfileSkeleton";
import { UpdateProfileForm } from "./UpdateProfileForm";

export const UpdateProfile = () => {
const {
data: profile,
isLoading,
isError,
error
} = useQuery({
queryKey: ["user-profile"],
queryFn: getUserProfileService
});

// Handle loading state
if (isLoading) return <UpdateProfileSkeleton />;

// Handle error state
if (isError) {
toast.error(error.message);
return (
<CustomError
className="mt-4 w-full border-none shadow-none"
title="We couldn't load your profile"
message={error.message}
showFooter={false}
/>
);
}

// Show an error if the profile is not loading but it's undefined
if (!profile)
return (
<CustomError
className="mt-4 w-full border-none shadow-none"
title="We couldn't load your profile"
showFooter={false}
/>
);

return (
<div>
{/* First letter of the user's full name */}
<span className="mx-auto my-4 grid aspect-square w-1/5 place-content-center rounded-md bg-purple-upb text-2xl font-bold text-white">
{profile.full_name[0]}
</span>
<UpdateProfileForm profile={profile} />
{/* Form to update the information */}
</div>
);
};
Loading