add page for teams
parent
917431f4e8
commit
60a4b8b29e
|
@ -0,0 +1,83 @@
|
|||
import React from "react";
|
||||
import Text from "@components/ui/Text";
|
||||
import Link from "next/link";
|
||||
import Avatar from "@components/Avatar";
|
||||
import { ArrowRightIcon } from "@heroicons/react/outline";
|
||||
import useTheme from "@components/Theme";
|
||||
import classnames from "classnames";
|
||||
|
||||
const Team = ({ team }) => {
|
||||
useTheme();
|
||||
|
||||
const Member = ({ member }) => {
|
||||
const classes = classnames(
|
||||
"group",
|
||||
"relative",
|
||||
"flex flex-col",
|
||||
"space-y-4",
|
||||
"p-4",
|
||||
"bg-white dark:bg-opacity-8",
|
||||
"border border-neutral-200",
|
||||
"hover:cursor-pointer",
|
||||
"hover:border-black hover:border-2 dark:border-neutral-700 dark:hover:border-neutral-600",
|
||||
"rounded-sm",
|
||||
"hover:shadow-md"
|
||||
);
|
||||
|
||||
return (
|
||||
<Link key={member.id} href={`/${member.user.username}`}>
|
||||
<div className={classes}>
|
||||
<ArrowRightIcon
|
||||
className={classnames(
|
||||
"text-black dark:text-white",
|
||||
"absolute top-4 right-4",
|
||||
"h-4 w-4",
|
||||
"transition-opacity",
|
||||
"opacity-0 group-hover:opacity-100 group-hover:block"
|
||||
)}
|
||||
/>
|
||||
|
||||
<Avatar user={member.user} className="w-12 h-12 rounded-full" />
|
||||
|
||||
<section className="space-y-2">
|
||||
<Text variant="title">{member.user.name}</Text>
|
||||
<Text variant="subtitle" className="w-6/8">
|
||||
{member.user.bio}
|
||||
</Text>
|
||||
</section>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const Members = ({ members }) => {
|
||||
if (!members || members.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="mx-auto min-w-full lg:min-w-lg max-w-5xl grid grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-x-12 gap-y-6">
|
||||
{members.map((member) => {
|
||||
return <Member key={member.id} member={member} />;
|
||||
})}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<article className="flex flex-col space-y-8 lg:space-y-12">
|
||||
<div className="mb-8 text-center">
|
||||
<Avatar
|
||||
user={{
|
||||
email: team.name,
|
||||
}}
|
||||
className="mx-auto w-20 h-20 rounded-full mb-4"
|
||||
/>
|
||||
<Text variant="headline">{team.name}</Text>
|
||||
</div>
|
||||
<Members members={team.members} />
|
||||
</article>
|
||||
);
|
||||
};
|
||||
|
||||
export default Team;
|
|
@ -0,0 +1,54 @@
|
|||
import { Team } from "@prisma/client";
|
||||
import prisma from "@lib/prisma";
|
||||
import logger from "@lib/logger";
|
||||
|
||||
const log = logger.getChildLogger({ prefix: ["[lib] getTeam"] });
|
||||
export const getTeam = async (idOrSlug: string): Promise<Team | null> => {
|
||||
const teamIdOrSlug = idOrSlug;
|
||||
|
||||
let team = null;
|
||||
|
||||
log.debug(`{teamIdOrSlug} ${teamIdOrSlug}`);
|
||||
|
||||
const teamSelectInput = {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
members: {
|
||||
where: {
|
||||
accepted: true,
|
||||
},
|
||||
select: {
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
email: true,
|
||||
name: true,
|
||||
bio: true,
|
||||
avatar: true,
|
||||
theme: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
team = await prisma.team.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
id: parseInt(teamIdOrSlug) || undefined,
|
||||
},
|
||||
{
|
||||
slug: teamIdOrSlug,
|
||||
},
|
||||
],
|
||||
},
|
||||
select: teamSelectInput,
|
||||
});
|
||||
|
||||
log.debug(`{team}`, { team });
|
||||
|
||||
return team;
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
import { GetServerSideProps } from "next";
|
||||
import Head from "next/head";
|
||||
|
||||
import Theme from "@components/Theme";
|
||||
import { getTeam } from "@lib/teams/getTeam";
|
||||
import Team from "@components/team/screens/Team";
|
||||
|
||||
export default function Page(props) {
|
||||
const { isReady } = Theme();
|
||||
|
||||
return (
|
||||
isReady && (
|
||||
<div>
|
||||
<Head>
|
||||
<title>{props.team.name} | Calendso</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
<main className="mx-auto py-24 px-4">
|
||||
<Team team={props.team} />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||
const teamIdOrSlug = Array.isArray(context.query?.idOrSlug)
|
||||
? context.query.idOrSlug.pop()
|
||||
: context.query.idOrSlug;
|
||||
|
||||
const team = await getTeam(teamIdOrSlug);
|
||||
|
||||
if (!team) {
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
team,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// Auxiliary methods
|
||||
export function getRandomColorCode(): string {
|
||||
let color = "#";
|
||||
for (let idx = 0; idx < 6; idx++) {
|
||||
color += Math.floor(Math.random() * 10);
|
||||
}
|
||||
return color;
|
||||
}
|
|
@ -95,22 +95,28 @@ module.exports = {
|
|||
inter: ["Inter", "sans-serif"],
|
||||
kollektif: ["Kollektif", "sans-serif"],
|
||||
},
|
||||
maxHeight: (theme) => ({
|
||||
maxHeight: (theme, { breakpoints }) => ({
|
||||
0: "0",
|
||||
97: "25rem",
|
||||
...theme("spacing"),
|
||||
...breakpoints(theme("screens")),
|
||||
...theme("screens"),
|
||||
full: "100%",
|
||||
screen: "100vh",
|
||||
}),
|
||||
minHeight: (theme) => ({
|
||||
minHeight: (theme, { breakpoints }) => ({
|
||||
0: "0",
|
||||
...theme("spacing"),
|
||||
...breakpoints(theme("screens")),
|
||||
...theme("screens"),
|
||||
full: "100%",
|
||||
screen: "100vh",
|
||||
}),
|
||||
minWidth: (theme) => ({
|
||||
minWidth: (theme, { breakpoints }) => ({
|
||||
0: "0",
|
||||
...theme("spacing"),
|
||||
...breakpoints(theme("screens")),
|
||||
...theme("screens"),
|
||||
full: "100%",
|
||||
screen: "100vw",
|
||||
}),
|
||||
|
@ -118,9 +124,23 @@ module.exports = {
|
|||
0: "0",
|
||||
...theme("spacing"),
|
||||
...breakpoints(theme("screens")),
|
||||
...theme("screens"),
|
||||
full: "100%",
|
||||
screen: "100vw",
|
||||
}),
|
||||
opacity: {
|
||||
0: "0",
|
||||
8: "0.08",
|
||||
10: "0.10",
|
||||
20: "0.20",
|
||||
40: "0.40",
|
||||
60: "0.60",
|
||||
80: "0.80",
|
||||
25: "0.25",
|
||||
50: "0.5",
|
||||
75: "0.75",
|
||||
100: "1",
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
|
|
Loading…
Reference in New Issue