Skip to content

Commit aef93d1

Browse files
committed
Add connections
1 parent c440587 commit aef93d1

File tree

12 files changed

+312
-66
lines changed

12 files changed

+312
-66
lines changed
Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import authOptions from "@/app/api/auth/[...nextauth]/authOptions";
12
import BlankPageWithMessage from "@/components/BlankPageMessage";
23
import List from "@/components/List";
3-
import { UserTile } from "@/components/user/UserTile";
4+
import ConnectionTile from "@/components/user/ConnectionTile";
45
import { CompanyService } from "@/services/CompanyService";
6+
import { UserService } from "@/services/UserService";
7+
import { getServerSession } from "next-auth";
58

69
interface CompanyConnectionsParams {
710
id: string;
@@ -14,19 +17,40 @@ export default async function CompanyConnections({
1417
}) {
1518
const { id: companyID } = params;
1619

17-
const connections = await CompanyService.getConnections(companyID);
20+
const session = (await getServerSession(authOptions))!;
1821

22+
const connections = await CompanyService.getConnections(
23+
session.cannonToken,
24+
companyID,
25+
);
1926
if (!connections) {
2027
return <BlankPageWithMessage message="Company connections not found!" />;
2128
}
2229

30+
const connectionsByUser = connections.reduce(
31+
(acc, c) => ({ ...acc, [c.from]: [...(acc[c.from] ?? []), c] }),
32+
{} as Record<string, Connection[]>,
33+
);
34+
const users = (
35+
await Promise.all(
36+
Object.keys(connectionsByUser).map((id) =>
37+
UserService.getUser(session.cannonToken, id),
38+
),
39+
)
40+
).sort((a, b) => a!.name.localeCompare(b!.name));
41+
2342
return (
2443
<div className="container mx-auto">
25-
<List title="Company connections">
26-
{connections.map((u) => (
27-
<UserTile key={u.id} user={u} />
28-
))}
29-
</List>
44+
{users.map(
45+
(u) =>
46+
u && (
47+
<List key={u.id} title={`${u.name}&apos;s connections`}>
48+
{connectionsByUser[u.id].map((c) => (
49+
<ConnectionTile key={c.to} connection={c} />
50+
))}
51+
</List>
52+
),
53+
)}
3054
</div>
3155
);
3256
}

src/app/(authenticated)/companies/[id]/page.tsx

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { Scan } from "lucide-react";
1515
import Link from "next/link";
1616
import { SocialNetwork } from "@/components/SocialNetwork";
1717
import BlankPageWithMessage from "@/components/BlankPageMessage";
18+
import ConnectionTile from "@/components/user/ConnectionTile";
1819

1920
interface CompanyParams {
2021
id: string;
@@ -32,20 +33,23 @@ export default async function Company({ params }: { params: CompanyParams }) {
3233
}
3334

3435
const companySessions = company.sessions?.sort((a, b) =>
35-
a.date.localeCompare(b.date)
36+
a.date.localeCompare(b.date),
3637
);
3738
const companyMembers = company.members?.sort((a, b) =>
38-
a.name.localeCompare(b.name)
39+
a.name.localeCompare(b.name),
3940
);
4041
const companyStands = company.stands?.sort((a, b) =>
41-
a.date.localeCompare(b.date)
42+
a.date.localeCompare(b.date),
4243
);
4344
const hereToday = isHereToday(company);
4445

45-
const session = await getServerSession(authOptions);
46+
const session = (await getServerSession(authOptions))!;
4647
const user: User | null = await UserService.getMe(session!.cannonToken);
4748

48-
const companyConnections = await CompanyService.getConnections(companyID);
49+
const companyConnections = await CompanyService.getConnections(
50+
session.cannonToken,
51+
companyID,
52+
);
4953

5054
return (
5155
<div className="container mx-auto">
@@ -115,19 +119,17 @@ export default async function Company({ params }: { params: CompanyParams }) {
115119
<StandDetails standDetails={company.standDetails} />
116120
)}
117121
{/* Connections */}
118-
{user &&
119-
(isCompany(user.role) || isMember(user.role)) &&
120-
companyConnections && (
121-
<List
122-
title="Company connections"
123-
link={`/companies/${companyID}/connections`}
124-
linkText="See all"
125-
>
126-
{companyConnections.slice(0, N_CONNECTIONS).map((u) => (
127-
<UserTile key={u.id} user={u} />
128-
))}
129-
</List>
130-
)}
122+
{user && isCompany(user.role) && !!companyConnections?.length && (
123+
<List
124+
title="Company connections"
125+
link={`/companies/${companyID}/connections`}
126+
linkText="See all"
127+
>
128+
{companyConnections.slice(0, N_CONNECTIONS).map((c) => (
129+
<ConnectionTile key={c.to} connection={c} />
130+
))}
131+
</List>
132+
)}
131133
</div>
132134
);
133135
}
Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
11
import authOptions from "@/app/api/auth/[...nextauth]/authOptions";
2+
import BlankPageWithMessage from "@/components/BlankPageMessage";
23
import List from "@/components/List";
4+
import ConnectionTile from "@/components/user/ConnectionTile";
35
import { UserService } from "@/services/UserService";
46
import { getServerSession } from "next-auth";
57

68
export default async function Connections() {
7-
const session = await getServerSession(authOptions);
8-
const user: User | null = await UserService.getMe(session!.cannonToken);
9+
const session = (await getServerSession(authOptions))!;
10+
11+
const connections = await UserService.getConnections(session.cannonToken);
12+
if (!connections) {
13+
return <BlankPageWithMessage message="Connections not found!" />;
14+
}
915

1016
return (
1117
<div className="container mx-auto">
12-
<List title="Connections"></List>
18+
<List title="Connections">
19+
{connections.length > 0 ? (
20+
connections.map((c) => <ConnectionTile key={c.to} connection={c} />)
21+
) : (
22+
<div>
23+
<p>1. Scan other user&apos;s QR-Code.</p>
24+
<p>2. Open user&apos;s page.</p>
25+
<p>3. And click on the connect button.</p>
26+
</div>
27+
)}
28+
</List>
1329
</div>
1430
);
1531
}

src/app/(authenticated)/profile/page.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import GridList from "@/components/GridList";
33
import List from "@/components/List";
44
import ListCard from "@/components/ListCard";
55
import AchievementTile from "@/components/user/AchievementTile";
6+
import ConnectionTile from "@/components/user/ConnectionTile";
67
import CurriculumVitae from "@/components/user/CurriculumVitae";
78
import ProfileHeader from "@/components/user/ProfileHeader";
89
import ProfileInformations from "@/components/user/ProfileInformations";
@@ -15,7 +16,7 @@ import { getServerSession } from "next-auth";
1516
import Link from "next/link";
1617

1718
const N_ACHIEVEMENTS = 5;
18-
// const N_CONNECTIONS = 3;
19+
const N_CONNECTIONS = 3;
1920

2021
export default async function Profile() {
2122
const session = (await getServerSession(authOptions))!;
@@ -24,9 +25,11 @@ export default async function Profile() {
2425

2526
const achievements = await AchievementService.getAchievements();
2627
const userAchievements = achievements?.filter((a) =>
27-
a.users?.includes(user.id)
28+
a.users?.includes(user.id),
2829
);
2930

31+
const userConnections = await UserService.getConnections(session.cannonToken);
32+
3033
return (
3134
<div className="container mx-auto">
3235
<ProfileHeader user={user} />
@@ -76,17 +79,17 @@ export default async function Profile() {
7679
</GridList>
7780

7881
{/* Connections */}
79-
{/* !!user.connections?.length && (
82+
{!!userConnections?.length && (
8083
<List
8184
title="Connections"
8285
link="/profile/connections"
8386
linkText="See all"
8487
>
85-
{user.connections.slice(0, N_CONNECTIONS).map((u) => (
86-
<UserTile key={u.id} user={u} />
88+
{userConnections.slice(0, N_CONNECTIONS).map((c) => (
89+
<ConnectionTile key={c.to} connection={c} />
8790
))}
8891
</List>
89-
) */}
92+
)}
9093
</div>
9194
);
9295
}
Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,52 @@
11
"use client";
22

3-
import { UserPlus } from "lucide-react";
3+
import { UserMinus, UserPlus } from "lucide-react";
44
import { ProfileButtonProps } from ".";
5+
import { UserService } from "@/services/UserService";
56

67
export default function ConnectButton({
78
cannonToken,
89
user,
910
otherUser,
11+
connections,
1012
}: ProfileButtonProps) {
1113
if (user.id === otherUser.id) return <></>;
1214

13-
return (
14-
<button className="button-primary text-sm">
15-
<UserPlus size={16} />
16-
Connect
17-
</button>
18-
);
15+
const connection = connections.find((c) => c.to === otherUser.id);
16+
17+
async function handleConnect() {
18+
const connection = await UserService.connect(cannonToken, otherUser.id);
19+
if (!connection) {
20+
alert("Failed to connect");
21+
}
22+
}
23+
24+
async function handleRemoveConnection() {
25+
const connection = await UserService.removeConnection(
26+
cannonToken,
27+
otherUser.id,
28+
);
29+
if (!connection) {
30+
alert("Failed to connect");
31+
}
32+
}
33+
34+
if (connection) {
35+
return (
36+
<button
37+
className="button-secondary text-sm"
38+
onClick={handleRemoveConnection}
39+
>
40+
<UserMinus size={16} />
41+
Remove connection
42+
</button>
43+
);
44+
} else {
45+
return (
46+
<button className="button-primary text-sm" onClick={handleConnect}>
47+
<UserPlus size={16} />
48+
Connect
49+
</button>
50+
);
51+
}
1952
}

src/app/(authenticated)/users/[id]/buttons/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export interface ProfileButtonProps {
66
cannonToken: string;
77
user: User;
88
otherUser: User;
9+
connections: Connection[];
910
}
1011

1112
export default function ProfileButtons(buttonProps: ProfileButtonProps) {

src/app/(authenticated)/users/[id]/page.tsx

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { getServerSession } from "next-auth";
1212
import UserSignOut from "@/components/UserSignOut";
1313
import BlankPageWithMessage from "@/components/BlankPageMessage";
1414
import ProfileButtons from "./buttons";
15+
import Notes from "@/components/user/Notes";
1516

1617
interface UserProfileParams {
1718
id: string;
@@ -35,9 +36,22 @@ export default async function UserProfile({
3536

3637
const achievements = await AchievementService.getAchievements();
3738
const userAchievements = achievements?.filter((a) =>
38-
a.users?.includes(userProfile.id)
39+
a.users?.includes(userProfile.id),
3940
);
4041

42+
const connections = await UserService.getConnections(session.cannonToken);
43+
const connection = connections?.find((c) => c.to === userProfile.id);
44+
45+
async function handleNotesUpdate(notes: string) {
46+
"use server";
47+
if (userProfile)
48+
await UserService.updateConnection(
49+
session.cannonToken,
50+
userProfile.id,
51+
notes,
52+
);
53+
}
54+
4155
return (
4256
<div className="container mx-auto">
4357
<ProfileHeader user={userProfile} />
@@ -46,24 +60,13 @@ export default async function UserProfile({
4660
cannonToken={session.cannonToken}
4761
user={user}
4862
otherUser={userProfile}
63+
connections={connections ?? []}
4964
/>
5065

5166
{/* Notes */}
52-
{/* <List title="Notes">
53-
{userNotes && userNotes.trim() !== "" ? (
54-
<ShowMore lines={3}>
55-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
56-
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
57-
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
58-
aliquip ex ea commodo consequat. Duis aute irure dolor in
59-
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
60-
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
61-
culpa qui officia deserunt mollit anim id est laborum.
62-
</ShowMore>
63-
) : (
64-
<ListCard title="Write a note" icon={NotebookPen} />
65-
)}
66-
</List> */}
67+
{connection && (
68+
<Notes notes={connection.notes} onNotesUpdate={handleNotesUpdate} />
69+
)}
6770

6871
{!isCompany(userProfile.role) &&
6972
(isCompany(user.role) || isMember(user.role)) && (
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import authOptions from "@/app/api/auth/[...nextauth]/authOptions";
2+
import { UserService } from "@/services/UserService";
3+
import { getServerSession } from "next-auth";
4+
import { UserTile } from "./UserTile";
5+
6+
interface ConnectionTileProps {
7+
connection: Connection;
8+
}
9+
10+
export default async function ConnectionTile({
11+
connection,
12+
}: ConnectionTileProps) {
13+
const session = (await getServerSession(authOptions))!;
14+
15+
const connectedUser = await UserService.getUser(
16+
session.cannonToken,
17+
connection.to,
18+
);
19+
20+
if (!connectedUser) return <></>;
21+
return <UserTile user={connectedUser} />;
22+
}

0 commit comments

Comments
 (0)