From 0b5ed1d0636da00dca3b8dda31e21b7ed2330a9c Mon Sep 17 00:00:00 2001 From: FeimeiChen <54688836+FeimeiChen@users.noreply.github.com> Date: Thu, 29 Feb 2024 12:40:43 -1000 Subject: [PATCH] Create Home page (Before and After Login) --- ui/public/cogs.svg | 0 ui/public/id-card-solid.svg | 1 + ui/public/id-email.svg | 0 ui/public/key-solid.svg | 1 + ui/public/uh-groupings-text.svg | 3 + ui/public/user-solid.svg | 1 + ui/public/watch.svg | 0 ui/public/wrench-solid.svg | 1 + ui/src/app/(index)/page.tsx | 69 ++++++++++++++++- ui/src/app/about/page.tsx | 60 ++------------- ui/src/components/AboutInfoItem.tsx | 23 ++++++ ui/src/components/UHGroupingsInfo.tsx | 48 ++++++++++++ ui/src/components/home/AfterLogin.tsx | 99 +++++++++++++++++++++++++ ui/src/components/home/Announcement.tsx | 16 ++++ ui/src/components/home/BeforeLogin.tsx | 29 ++++++++ ui/src/components/home/LoginButton.tsx | 28 +++++++ ui/src/components/home/UserInfoItem.tsx | 49 ++++++++++++ ui/src/components/ui/alert.tsx | 61 +++++++++++++++ ui/src/components/ui/button.tsx | 10 ++- ui/tailwind.config.ts | 12 ++- 20 files changed, 449 insertions(+), 62 deletions(-) mode change 100755 => 100644 ui/public/cogs.svg create mode 100644 ui/public/id-card-solid.svg mode change 100755 => 100644 ui/public/id-email.svg create mode 100644 ui/public/key-solid.svg create mode 100644 ui/public/uh-groupings-text.svg create mode 100644 ui/public/user-solid.svg mode change 100755 => 100644 ui/public/watch.svg create mode 100644 ui/public/wrench-solid.svg create mode 100644 ui/src/components/AboutInfoItem.tsx create mode 100644 ui/src/components/UHGroupingsInfo.tsx create mode 100644 ui/src/components/home/AfterLogin.tsx create mode 100644 ui/src/components/home/Announcement.tsx create mode 100644 ui/src/components/home/BeforeLogin.tsx create mode 100644 ui/src/components/home/LoginButton.tsx create mode 100644 ui/src/components/home/UserInfoItem.tsx create mode 100644 ui/src/components/ui/alert.tsx diff --git a/ui/public/cogs.svg b/ui/public/cogs.svg old mode 100755 new mode 100644 diff --git a/ui/public/id-card-solid.svg b/ui/public/id-card-solid.svg new file mode 100644 index 00000000..8abeb2c8 --- /dev/null +++ b/ui/public/id-card-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/public/id-email.svg b/ui/public/id-email.svg old mode 100755 new mode 100644 diff --git a/ui/public/key-solid.svg b/ui/public/key-solid.svg new file mode 100644 index 00000000..7555f7ed --- /dev/null +++ b/ui/public/key-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/public/uh-groupings-text.svg b/ui/public/uh-groupings-text.svg new file mode 100644 index 00000000..f323aed7 --- /dev/null +++ b/ui/public/uh-groupings-text.svg @@ -0,0 +1,3 @@ + + + diff --git a/ui/public/user-solid.svg b/ui/public/user-solid.svg new file mode 100644 index 00000000..30cbd7d3 --- /dev/null +++ b/ui/public/user-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/public/watch.svg b/ui/public/watch.svg old mode 100755 new mode 100644 diff --git a/ui/public/wrench-solid.svg b/ui/public/wrench-solid.svg new file mode 100644 index 00000000..280b3bd0 --- /dev/null +++ b/ui/public/wrench-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/src/app/(index)/page.tsx b/ui/src/app/(index)/page.tsx index b0223723..adbde1a3 100644 --- a/ui/src/app/(index)/page.tsx +++ b/ui/src/app/(index)/page.tsx @@ -1,7 +1,70 @@ -const Home = () => { +import Image from 'next/image'; +import BeforeLogin from '@/components/home/BeforeLogin'; +import AfterLogin from '@/components/home/AfterLogin'; +import {getCurrentUser} from '@/access/AuthenticationService'; +import Role from '@/access/Role'; +import LoginButton from '@/components/home/LoginButton'; +import {getAnnouncements, getNumberOfGroupings, getNumberOfMemberships} from '@/services/GroupingsApiService'; +import Announcement from '@/components/home/Announcement'; + +const Home = async () => { + const [currentUser, numberOfGroupings, numberOfMemberships, announcements] = await Promise.all([ + getCurrentUser(), + getNumberOfGroupings(), + getNumberOfMemberships(), + getAnnouncements() + ]); + + const activeAnnouncements = announcements.announcements + .filter((announcement) => announcement.state === 'Active') + .map((announcement) => announcement.message); + + return ( - null +
+
+ {activeAnnouncements.map((announcement: string, index: number) => ( + + ))} +
+
+
+

UH Groupings

+ UH Groupings logotype + +

Manage your groupings in one place, use them in many.

+
+ {!currentUser.roles.includes(Role.UH) && + } +
+
+
+
+ UH Groupings +
+
+
+ + {currentUser.roles.includes(Role.UH) ? ( + + ) : ( + + )} +
); } - export default Home; diff --git a/ui/src/app/about/page.tsx b/ui/src/app/about/page.tsx index c8d17f53..92d02ce0 100644 --- a/ui/src/app/about/page.tsx +++ b/ui/src/app/about/page.tsx @@ -1,58 +1,8 @@ -import Image from 'next/image'; +import UHGroupingsInfo from '@/components/UHGroupingsInfo'; const About = () => (
-
-
-
-

What is a UH Grouping?

-

A grouping is a collection of members - (e.g., all full-time - Hilo faculty).

-
-
-
-
- Cogs icon -
-

Create groupings, manage grouping memberships, - control members' self-service - options, designate sync destinations, and more.

-
- -
-
- Email icon -
-

Synchronize groupings email LISTSERV lists, attributes for access - control via - CAS and LDAP, etc.

-
- -
-
- Watch icon -
-

Leverage group data from official sources, which can - substantially reduce the - manual overhead of membership management.

-
-
-
-
- +

GENERAL INFO

@@ -60,8 +10,10 @@ const About = () => (

How do I request a new grouping?

A request form is available. + href={'https://uhawaii.atlassian.net/wiki/spaces/UHIAM/' + + 'pages/13402308/UH+Groupings+Request+Form'} + aria-label="A request form is available">A request form is available + .

Exactly what is a grouping?

diff --git a/ui/src/components/AboutInfoItem.tsx b/ui/src/components/AboutInfoItem.tsx new file mode 100644 index 00000000..fc81ce39 --- /dev/null +++ b/ui/src/components/AboutInfoItem.tsx @@ -0,0 +1,23 @@ +import Image from 'next/image'; + +const AboutInfoItem = ({src, alt, description, variant}: { + src: string, + alt: string, + description: string, + variant?: 'default'| 'home' +}) => { + const size = variant === 'home'? 'text-1.2': 'text-base'; + return ( +
+
+ {alt} +
+

{description}

+
+ ); +} +export default AboutInfoItem; diff --git a/ui/src/components/UHGroupingsInfo.tsx b/ui/src/components/UHGroupingsInfo.tsx new file mode 100644 index 00000000..f599fae1 --- /dev/null +++ b/ui/src/components/UHGroupingsInfo.tsx @@ -0,0 +1,48 @@ +import AboutInfoItem from '@/components/AboutInfoItem'; + + +const UHGroupingsInfo = ( + { variant + }: { + variant?: 'default' | 'home'; + }) => { + const h1Color = variant === 'home' ? 'text-text-color' : 'text-uh-black'; + const page = variant === 'home' ? 'home': 'default'; + return ( +
+
+
+
+

What is a UH Grouping?

+

A grouping is a collection of members + (e.g., all full-time + Hilo faculty).

+
+
+ + + +
+
+
+
+ ); + +} + +export default UHGroupingsInfo; diff --git a/ui/src/components/home/AfterLogin.tsx b/ui/src/components/home/AfterLogin.tsx new file mode 100644 index 00000000..1a878bb0 --- /dev/null +++ b/ui/src/components/home/AfterLogin.tsx @@ -0,0 +1,99 @@ +import User from '@/access/User'; +import Role from '@/access/Role'; +import Image from 'next/image'; +import {KeyRound} from 'lucide-react'; +import UserInfoItem from '@/components/home/UserInfoItem'; + +const AfterLogin = ( + { + currentUser, + numberOfGroupings, + numberOfMemberships + }: { + currentUser: User, + numberOfGroupings: number, + numberOfMemberships: number + }) => { + const isAdmin = currentUser.roles.includes(Role.ADMIN); + const isOwner = currentUser.roles.includes(Role.OWNER); + const getHighestRole = () => { + if (isAdmin) { + return 'Admin'; + } else if (isOwner) { + return 'Owner'; + } else { + return 'Member'; + } + } + + return ( +
+
+
+
+
+
+ user-solid +
+ +
+
+
+
+

Welcome, {currentUser.firstName}!

+

Role: {getHighestRole()}

+
+
+
+
+ +
+ {isAdmin && } + + {isOwner && } +
+
+ ); +} + +export default AfterLogin; diff --git a/ui/src/components/home/Announcement.tsx b/ui/src/components/home/Announcement.tsx new file mode 100644 index 00000000..97b8cbae --- /dev/null +++ b/ui/src/components/home/Announcement.tsx @@ -0,0 +1,16 @@ +'use client'; +import {Alert, AlertDescription} from '@/components/ui/alert'; + +const Announcement = ({announcement}: { announcement: string } +) => { + + return ( + + + {announcement} + + + ); +}; + +export default Announcement; diff --git a/ui/src/components/home/BeforeLogin.tsx b/ui/src/components/home/BeforeLogin.tsx new file mode 100644 index 00000000..d672289e --- /dev/null +++ b/ui/src/components/home/BeforeLogin.tsx @@ -0,0 +1,29 @@ +import {Button} from '@/components/ui/button'; +import Link from 'next/link'; +import {ArrowRight} from 'lucide-react'; +import UHGroupingsInfo from '@/components/UHGroupingsInfo'; + +const BeforeLogin = () => { + return ( +
+ +
+
+ +
+
+
+ ); +}; + +const LearnMoreButton = () => { + return ( + + + + ); +}; + +export default BeforeLogin; diff --git a/ui/src/components/home/LoginButton.tsx b/ui/src/components/home/LoginButton.tsx new file mode 100644 index 00000000..eb33e252 --- /dev/null +++ b/ui/src/components/home/LoginButton.tsx @@ -0,0 +1,28 @@ +'use client'; + +import {Button} from '@/components/ui/button'; +import Role from '@/access/Role'; +import User from '@/access/User'; +import {login, logout} from '@/access/AuthenticationService'; + +const LoginButton = ({currentUser}: { currentUser: User; }) => ( + <> + {!currentUser.roles.includes(Role.UH) ? ( + + ) : ( + + )} + +); + +export default LoginButton; diff --git a/ui/src/components/home/UserInfoItem.tsx b/ui/src/components/home/UserInfoItem.tsx new file mode 100644 index 00000000..3362aa67 --- /dev/null +++ b/ui/src/components/home/UserInfoItem.tsx @@ -0,0 +1,49 @@ +import Image from 'next/image'; +import Link from 'next/link'; +import {Button} from '@/components/ui/button'; + +const UserInfoItem = ( + { + alt, + src, + number, + show, + title, + description, + link, + text + }: { + alt: string, + src: string, + number: number, + show: boolean, + title: string, + description: string, + link: string, + text: string + }) => { + return ( +
+
+
+ {alt} + {show && {number}} +
+

{title}

+

{description}

+
+ + + +
+ ); +} + +export default UserInfoItem; diff --git a/ui/src/components/ui/alert.tsx b/ui/src/components/ui/alert.tsx new file mode 100644 index 00000000..b4092ae8 --- /dev/null +++ b/ui/src/components/ui/alert.tsx @@ -0,0 +1,61 @@ +import * as React from 'react' +import { cva, type VariantProps } from 'class-variance-authority' + +import { cn } from '@/components/ui/utils' + +const alertVariants = cva( + // eslint-disable-next-line @stylistic/max-len + 'relative w-full rounded-lg border border-slate-200 p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-slate-950 dark:border-slate-800 dark:[&>svg]:text-slate-50', + { + variants: { + variant: { + default: 'bg-white text-slate-950 dark:bg-slate-950 dark:text-slate-50', + destructive: + // eslint-disable-next-line @stylistic/max-len + 'border-red-500/50 text-red-500 dark:border-red-500 [&>svg]:text-red-500 dark:border-red-900/50 dark:text-red-900 dark:dark:border-red-900 dark:[&>svg]:text-red-900', + }, + }, + defaultVariants: { + variant: 'default', + }, + } +) + +const Alert = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes & VariantProps +>(({ className, variant, ...props }, ref) => ( +
+)) +Alert.displayName = 'Alert' + +const AlertTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +AlertTitle.displayName = 'AlertTitle' + +const AlertDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +AlertDescription.displayName = 'AlertDescription' + +export { Alert, AlertTitle, AlertDescription } diff --git a/ui/src/components/ui/button.tsx b/ui/src/components/ui/button.tsx index 60a2e796..8f392f48 100644 --- a/ui/src/components/ui/button.tsx +++ b/ui/src/components/ui/button.tsx @@ -6,13 +6,15 @@ import { cn } from '@/components/ui/utils'; const buttonVariants = cva( `inline-flex items-center justify-center whitespace-nowrap rounded-[0.25rem] text-base font-normal ring-offset-white - transition-colors ease-in-out duration-150 focus-visible:outline-none focus-visible:ring-2 + transition-color ease-in-out duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300`, { variants: { variant: { - default: `bg-[#5a9cb4] hover:bg-green-blue [text-shadow:_0_1px_1px_#444] text-slate-50`, + default: `bg-[#6fa9be] border-transparent text-slate-50 [text-shadow:_0_1px_1px_#444] bg-gradient-to-b + from-[#7db1c4] to-[#5a9cb4] border-[1px] hover:from-green-blue hover:to-green-blue + border-x-black/[.0.1] border-t-black/[.0.1] border-b-black/[.0.25]`, destructive: `bg-red-500 text-slate-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/90`, outline: `border border-green-blue bg-white hover:bg-green-blue hover:text-white text-uh-teal`, @@ -23,8 +25,8 @@ const buttonVariants = cva( }, size: { default: 'h-10 px-2.5 py-2', - sm: 'h-9 rounded-md px-2', - lg: 'h-11 rounded-md px-8', + sm: 'h-9 px-2', + lg: 'h-12 px-4 text-xl', icon: 'h-10 w-10', }, }, diff --git a/ui/tailwind.config.ts b/ui/tailwind.config.ts index 778cc5dd..80411c93 100644 --- a/ui/tailwind.config.ts +++ b/ui/tailwind.config.ts @@ -21,14 +21,24 @@ const config = { } }, extend: { + fontSize: { + '2.5': '2.5rem', + '1.25': '1.25rem', + '1.2': '1.2rem', + '1.125': '1.125rem', + '1.75':'1.75rem' + + }, colors: { 'green-blue': '#004e59', 'uh-black': '#212121', 'uh-teal': '#0d7078', 'seafoam': '#e3f2ef', 'text-color': '#1c6070', + 'text-primary': '#004252', 'link-color' : '#006ffa', - 'link-hover-color' : '#0056b3' + 'link-hover-color' : '#0056b3', + 'blue-background': '#00a6b2' }, fontFamily: { 'source-sans-3': ['var(--font-source-sans-3)', 'Helvetica', 'Arial', 'sans-serif'],