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(profile): Add other user's profile detail in appointment #722

Merged
merged 11 commits into from
Mar 26, 2024
2 changes: 1 addition & 1 deletion app/web/__tests__/ProfileDetail.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ProfileDetails } from "@components/profile/ProfileDetails";
import "@testing-library/jest-dom";
import { ProfileDetails } from "@components/user/ProfileDetails";
import { render, screen } from "@testing-library/react";
import { User } from "next-auth";

Expand Down
4 changes: 2 additions & 2 deletions app/web/__tests__/__snapshots__/ProfilePicture.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ exports[`ProfilePicture matches snapshot 1`] = `
"baseElement": <body>
<div>
<a
href="/user/profile"
href="/profile"
style="display: flex; flex-direction: column; align-items: center; margin: 0.5rem 0px; text-decoration: none;"
>
<img
Expand All @@ -30,7 +30,7 @@ exports[`ProfilePicture matches snapshot 1`] = `
</body>,
"container": <div>
<a
href="/user/profile"
href="/profile"
style="display: flex; flex-direction: column; align-items: center; margin: 0.5rem 0px; text-decoration: none;"
>
<img
Expand Down
15 changes: 15 additions & 0 deletions app/web/src/app/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@ export async function getAllUserData() {
return users;
}

export async function getUserByUsername(
username: string,
): Promise<CognitoUser | null> {
try {
const users = await getUsrList("username", username);
if (users && users.length > 0) {
return users[0];
}
return null;
} catch (error) {
console.error("Error fetching user by username:", error);
return null;
}
}

export async function getUserAppointments(user: User) {
const appointments = await db.appointment.findMany({
where: {
Expand Down
40 changes: 40 additions & 0 deletions app/web/src/app/profile/[withUser]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright [2023] [Privacypal Authors]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { OtherUserProfileDetails } from "@components/profile/OtherUserProfileDetails";
import React from "react";
import { auth } from "src/auth";
import { Metadata } from "next";

export const metadata: Metadata = {
title: "Other User Profile Detail",
};

export default async function OtherUserProfilePage({
params,
}: {
params: { withUser: string };
}) {
const session = await auth();
if (!session) {
return <main>Not logged in</main>;
}
return (
<main>
<OtherUserProfileDetails withUser={params.withUser} user={session.user} />
</main>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
* limitations under the License.
*/
import Content from "@components/layout/Content";
import { ProfileDetails } from "@components/user/ProfileDetails";
import UserUpdateForm from "@components/user/UserUpdateForm";
import { ProfileDetails } from "@components/profile/ProfileDetails";
import { auth } from "src/auth";
import { Metadata } from "next";

export const metadata: Metadata = {
title: "Profile Detail",
};

export default async function UserDashboardPage() {
const session = await auth();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const ConversationDropdownMenu = () => {
<DropdownItem value={0} key="action" to="/user">
Homepage
</DropdownItem>
<DropdownItem value={2} key="profile" to="/user/profile">
<DropdownItem value={2} key="profile" to="/profile">
Profile
</DropdownItem>
<DropdownItem value={3} key="signout">
Expand Down
5 changes: 2 additions & 3 deletions app/web/src/components/appointment/inbox/ConversationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ const userMetaStyle: CSS = {
};

const profileLinkStyle: CSS = {
fontSize: "0.75rem",
fontSize: "1rem",
};

interface ConversationListProps {
Expand Down Expand Up @@ -166,8 +166,7 @@ export const ConversationList = ({
</Title>
<span style={userMetaStyle}>{user.email}</span>
</div>
{/* TODO: possibly remove this link (do users have profiles?) */}
<Link href="/user/profile" style={profileLinkStyle}>
<Link href="/profile" style={profileLinkStyle}>
View Profile
</Link>
</PanelFooter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
* limitations under the License.
*/
"use client";

import { Panel, PanelHeader, PanelMain, Title } from "@patternfly/react-core";
import { InboxAvatar } from "./InboxAvatar";
import pfAvatar from "@assets/pf_avatar.svg";
import { CSS } from "@lib/utils";
import { User } from "next-auth";
import { CognitoUser } from "@lib/cognito";
import Link from "next/link";

const panelStyle: CSS = {
display: "flex",
Expand Down Expand Up @@ -86,15 +86,14 @@ interface ConversationViewerProps {
withUser: CognitoUser | undefined;
children?: React.ReactNode;
}

export const ConversationViewer = ({
withUser,
children,
}: ConversationViewerProps) => {
const headerText = withUser
? withUser.firstName + " " + withUser.lastName
: "No appointment selected.";

const profilepage = `/profile/${withUser?.username}`;
return (
<Panel style={panelStyle}>
<PanelHeader style={headerStyle}>
Expand All @@ -107,6 +106,7 @@ export const ConversationViewer = ({
<span style={userMetaStyle}>{withUser.email}</span>
) : null}
</div>
{withUser && <Link href={profilepage}>View profile</Link>}
</PanelHeader>
<PanelMain style={panelBodyStyle}>{children}</PanelMain>
</Panel>
Expand Down
2 changes: 1 addition & 1 deletion app/web/src/components/layout/ProfilePicture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export default function ProfilePicture({
// link to dashboard in place of user profile
const avatar = (
<Link
href={link ?? "/user/profile"}
href={link ?? "/profile"}
style={{ ...styles.link, ...style }}
title={tooltip}
>
Expand Down
163 changes: 163 additions & 0 deletions app/web/src/components/profile/OtherUserProfileDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* Copyright [2023] [Privacypal Authors]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
"use client";
import React, { useEffect, useState } from "react";
import {
Card,
CardTitle,
CardBody,
CardHeader,
Flex,
Title,
FlexItem,
Divider,
CardFooter,
Alert,
} from "@patternfly/react-core";
import { User } from "next-auth";
import { UserRole } from "@lib/userRole";
import { CognitoUser } from "@lib/cognito";
import { getUserByUsername } from "@app/actions";
import { CSS } from "@lib/utils";

const cardContainer: CSS = {
display: "flex",
justifyContent: "center",
filter: "drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25))",
};

const cardStyle: CSS = {
width: "25%",
};

interface ProfileDetailsProps {
user: User;
withUser: string;
}

export const OtherUserProfileDetails = ({
user,
withUser,
}: ProfileDetailsProps) => {
const [userDetails, setUserDetails] = useState<CognitoUser | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);

useEffect(() => {
const fetchUserDetails = async () => {
try {
const user = await getUserByUsername(withUser);
if (user) {
setUserDetails(user);
setLoading(false);
} else {
setLoading(false);
setError("User details not found");
}
} catch (error) {
console.error("Error fetching user details:", error);
setLoading(false);
setError("Error fetching user details");
}
};

fetchUserDetails();
}, [withUser]);

if (loading) {
return <div>Loading...</div>;
}

if (error) {
return (
<Alert variant="danger" title={error} style={{ marginTop: "1rem" }} />
);
}

if (!userDetails) {
return (
<Alert
variant="danger"
title="User details not found."
style={{ marginTop: "1rem" }}
/>
);
}

const withUserRole =
user.role === UserRole.PROFESSIONAL
? UserRole.CLIENT
: UserRole.PROFESSIONAL;

return (
<div style={cardContainer}>
<Card aria-label="Personal Information" style={cardStyle}>
<CardHeader style={{ textAlign: "center", marginBottom: "0.5rem" }}>
<CardTitle
component="h2"
style={{ fontSize: "2rem", fontWeight: "bold", margin: 0 }}
>
Professional's Information
</CardTitle>
</CardHeader>

<CardBody>
<Divider />
<Flex
direction={{ default: "row" }}
alignItems={{ default: "alignItemsFlexStart" }}
justifyContent={{ default: "justifyContentSpaceBetween" }}
grow={{ default: "grow" }}
>
<FlexItem>
<Flex direction={{ default: "column" }}>
<FlexItem>
<Title headingLevel="h2">Username:</Title>
<span>{userDetails.username}</span>
</FlexItem>

<FlexItem>
<Title headingLevel="h2">Email:</Title>
<span>{userDetails.email}</span>
</FlexItem>

<FlexItem>
<Title headingLevel="h2">Full Name:</Title>
<span>
{userDetails.firstName} {userDetails.lastName}
</span>
</FlexItem>
<FlexItem>
<Title headingLevel="h2">Role:</Title>
<span>{withUserRole}</span>
</FlexItem>
</Flex>
</FlexItem>

<FlexItem>
{/* <ProfilePicture
tooltip={`Logged in as ${user.username}`}
user={user}
style={{ marginLeft: "1rem" }}
width="100px"
/> */}
</FlexItem>
</Flex>
</CardBody>
</Card>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ import {
import ProfilePicture from "@components/layout/ProfilePicture";
import { User } from "next-auth";
import Link from "next/link";
import { UserRole } from "@lib/userRole";
import { CognitoUser } from "@lib/cognito";
interface ProfileDetailsProps {
user: User;
}
Expand All @@ -48,7 +46,7 @@ export const ProfileDetails = ({ user }: ProfileDetailsProps) => {
<CardBody>
<Divider></Divider>
<Flex
direction={{ default: "row" }} // Set direction to "row"
direction={{ default: "row" }}
alignItems={{ default: "alignItemsFlexStart" }}
justifyContent={{ default: "justifyContentSpaceBetween" }}
grow={{ default: "grow" }}
Expand Down
Loading