diff --git a/.gitignore b/.gitignore index 468aaa42..a32db3db 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,6 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +# generic name for files that shouldn't be checked in (handy for mock data) +*.temp* diff --git a/package-lock.json b/package-lock.json index 60ec0d62..b616d328 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rdpc-ui", - "version": "0.2.0", + "version": "0.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rdpc-ui", - "version": "0.2.0", + "version": "0.4.0", "dependencies": { "@hookform/resolvers": "^3.1.1", "@icgc-argo/ego-token-utils": "^8.2.0", @@ -39,6 +39,7 @@ "husky": "^8.0.3", "lint-staged": "^13.2.2", "prettier": "2.8.8", + "prettier-plugin-organize-imports": "^3.2.2", "typescript": "^5.1.3" }, "peerDependencies": { @@ -4900,6 +4901,26 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-plugin-organize-imports": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.2.tgz", + "integrity": "sha512-e97lE6odGSiHonHJMTYC0q0iLXQyw0u5z/PJpvP/3vRy6/Zi9kLBwFAbEGjDzIowpjQv8b+J04PDamoUSQbzGA==", + "dev": true, + "peerDependencies": { + "@volar/vue-language-plugin-pug": "^1.0.4", + "@volar/vue-typescript": "^1.0.4", + "prettier": ">=2.0", + "typescript": ">=2.9" + }, + "peerDependenciesMeta": { + "@volar/vue-language-plugin-pug": { + "optional": true + }, + "@volar/vue-typescript": { + "optional": true + } + } + }, "node_modules/promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", diff --git a/package.json b/package.json index b7b2c81e..cc290082 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rdpc-ui", - "version": "0.3.0", + "version": "0.4.0", "private": true, "scripts": { "dev": "next dev", @@ -46,6 +46,7 @@ "husky": "^8.0.3", "lint-staged": "^13.2.2", "prettier": "2.8.8", + "prettier-plugin-organize-imports": "^3.2.2", "typescript": "^5.1.3" }, "lint-staged": { diff --git a/src/app/components/Header.tsx b/src/app/components/Header.tsx index 9c25019f..81bf4e7e 100644 --- a/src/app/components/Header.tsx +++ b/src/app/components/Header.tsx @@ -18,15 +18,43 @@ */ 'use client'; -import { AppBar, css, DnaLoader, UserBadge } from '@icgc-argo/uikit'; -import Link from 'next/link'; -import Image from 'next/image'; -import argoLogo from '/public/argo-logo.svg'; import { useAuthContext } from '@/global/utils/auth'; +import { css, useTheme } from '@/lib/emotion'; +import { AppBar, AppBarMenuItem, DnaLoader, Link, NavElement } from '@icgc-argo/uikit'; +import Image from 'next/image'; +import { usePathname } from 'next/navigation'; +import { useState } from 'react'; import LoginButton from './LoginButton'; +import ProfileMenu from './ProfileMenu'; +import argoLogo from '/public/argo-logo.svg'; const Header = () => { - const { egoJwt, loggingIn } = useAuthContext(); + const [isDropdownOpen, setDropdownOpen] = useState(false); + const { egoJwt, authLoading, logOut } = useAuthContext(); + const path = usePathname(); + const theme = useTheme(); + const onProfilePage = path === '/landing-page'; + const profileActive = onProfilePage && !!egoJwt.length && !authLoading; + + const profileNavDetails: Array = [ + { + active: profileActive, + href: '/landing-page', + name: 'Profile & Token', + LinkComp: Link, + }, + { + isLink: false, + onClick: () => { + setDropdownOpen(false); + logOut(); + }, + name: 'Logout', + active: false, + href: '', + LinkComp: Link, + }, + ]; return (
@@ -43,21 +71,28 @@ const Header = () => { {/** keep this div. header will have more items, will be "right-aligned" */}
- {egoJwt ? ( - - ) : loggingIn ? ( - - ) : ( - - )} + + {egoJwt ? ( + { + setDropdownOpen(!isDropdownOpen); + }} + profileNavDetails={profileNavDetails} + theme={theme} + /> + ) : authLoading ? ( + + ) : ( + + )} +
diff --git a/src/app/components/ProfileMenu.tsx b/src/app/components/ProfileMenu.tsx new file mode 100644 index 00000000..82993524 --- /dev/null +++ b/src/app/components/ProfileMenu.tsx @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of + * the GNU Affero General Public License v3.0. You should have received a copy of the + * GNU Affero General Public License along with this program. + * If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +'use client'; + +import { css } from '@/lib/emotion'; +import { DropdownMenu, FocusWrapper, NavBarElement, NavElement, UserBadge } from '@icgc-argo/uikit'; +import { Theme } from '@icgc-argo/uikit/ThemeProvider'; + +const ProfileMenu = ({ + isDropdownOpen, + onProfilePage, + onClick, + profileNavDetails, + theme, +}: { + isDropdownOpen: boolean; + onProfilePage: boolean; + onClick: () => void; + profileNavDetails: NavElement[]; + theme: Theme; +}) => ( + + {isDropdownOpen && ( + + {profileNavDetails.map((element, idx) => ( + + ))} + + )} + + +); + +export default ProfileMenu; diff --git a/src/app/landing-page/page.tsx b/src/app/landing-page/page.tsx index a9a628bb..1953ed6f 100644 --- a/src/app/landing-page/page.tsx +++ b/src/app/landing-page/page.tsx @@ -19,10 +19,10 @@ 'use client'; import { getAppConfig } from '@/global/config'; -import { logOut } from '@/global/utils/auth'; export default function LandingPage() { const { EGO_CLIENT_ID } = getAppConfig(); + return (
@@ -32,11 +32,6 @@ export default function LandingPage() {

Welcome! {EGO_CLIENT_ID}

-
- - - -
); } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 0f1def7f..6e01a109 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -22,10 +22,9 @@ */ 'use client'; -import { Work_Sans } from 'next/font/google'; +import { AuthProvider } from '@/global/utils/auth'; import { ReactNode } from 'react'; import { QueryClient, QueryClientProvider } from 'react-query'; -import { AuthProvider } from '@/global/utils/auth'; import Header from './components/Header'; import ThemeProvider from './components/ThemeProvider'; import { css } from '@/lib/emotion'; diff --git a/src/app/logging-in/page.tsx b/src/app/logging-in/page.tsx index d5f592e2..9069065f 100644 --- a/src/app/logging-in/page.tsx +++ b/src/app/logging-in/page.tsx @@ -22,20 +22,20 @@ import { useRouter } from 'next/navigation'; import { useQuery } from 'react-query'; import urlJoin from 'url-join'; -import { css, DnaLoader, useTheme } from '@icgc-argo/uikit'; import { getAppConfig } from '@/global/config'; -import { storeToken, useAuthContext } from '@/global/utils/auth'; +import { useAuthContext } from '@/global/utils/auth'; +import { DnaLoader, css, useTheme } from '@icgc-argo/uikit'; export default async function LoggingIn() { const { EGO_API_ROOT, EGO_CLIENT_ID } = getAppConfig(); const router = useRouter(); const theme = useTheme(); - const { egoJwt, setEgoJwt, loggingIn, setLoggingIn } = useAuthContext(); + const { egoJwt, authLoading, setAuthLoading, logIn } = useAuthContext(); const egoLoginUrl = urlJoin(EGO_API_ROOT, `/api/oauth/ego-token?client_id=${EGO_CLIENT_ID}`); if (egoJwt) router.push('/landing-page'); - if (!loggingIn && !egoJwt) setLoggingIn(true); + if (!authLoading && !egoJwt) setAuthLoading(true); useQuery('egoJwt', () => { fetch(egoLoginUrl, { @@ -47,9 +47,7 @@ export default async function LoggingIn() { }) .then(async (res) => { const newToken = await res.text(); - storeToken(newToken); - setEgoJwt(newToken); - setLoggingIn(false); + logIn(newToken); }) .catch(console.error); }); diff --git a/src/app/page.tsx b/src/app/page.tsx index 7a992c2e..d4562448 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -18,13 +18,12 @@ */ 'use client'; -import { ComponentType } from 'react'; -import Image from 'next/image'; -import urlJoin from 'url-join'; -import { DataCallout, Link, Typography, overtureLogo } from '@icgc-argo/uikit'; import { getAppConfig } from '@/global/config'; import { css, useTheme } from '@/lib/emotion'; -import Footer from './components/Footer'; +import { DataCallout, Link, Typography, overtureLogo } from '@icgc-argo/uikit'; +import Image from 'next/image'; +import { ComponentType } from 'react'; +import urlJoin from 'url-join'; import Hero from './components/Hero'; const { DOCS_URL_ROOT } = getAppConfig(); diff --git a/src/app/submission/[shortName]/page.tsx b/src/app/submission/[shortName]/page.tsx new file mode 100644 index 00000000..68f2af1b --- /dev/null +++ b/src/app/submission/[shortName]/page.tsx @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of + * the GNU Affero General Public License v3.0. You should have received a copy of the + * GNU Affero General Public License along with this program. + * If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +'use client'; + +export default function Program() { + return
Program
; +} diff --git a/src/app/submission/components/ProgramList.tsx b/src/app/submission/components/ProgramList.tsx new file mode 100644 index 00000000..0f51ff2c --- /dev/null +++ b/src/app/submission/components/ProgramList.tsx @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of + * the GNU Affero General Public License v3.0. You should have received a copy of the + * GNU Affero General Public License along with this program. + * If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +'use client'; + +import { useTheme } from '@/lib/emotion'; +import { Table, Typography, css } from '@icgc-argo/uikit'; +import { columns } from '../tableConfig'; + +export type ProgramsData = { + shortName: string; + name: string | null; + cancerTypes: Array; + countries: Array | null; + membershipType: ArgoMembershipKey; + genomicDonors: number | null; + submittedDonors: number; + commitmentDonors: number; + administrators: { firstName: string; lastName: string; email: string }[]; + donorPercentage: number; +}; + +export type ArgoMembershipKey = 'FULL' | 'ASSOCIATE'; + +export default function ProgramList({ programs }: { programs: ProgramsData[] }) { + const theme = useTheme(); + const programsArraySize = programs.length; + + return ( +
+ + {programsArraySize.toLocaleString()} results + + + + ); +} diff --git a/src/app/submission/components/ProgramMenu.tsx b/src/app/submission/components/ProgramMenu.tsx new file mode 100644 index 00000000..5708e868 --- /dev/null +++ b/src/app/submission/components/ProgramMenu.tsx @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of + * the GNU Affero General Public License v3.0. You should have received a copy of the + * GNU Affero General Public License along with this program. + * If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +'use client'; + +export default function ProgramMenu({ + programs, + searchQuery, +}: { + programs: { shortName: string }[]; + searchQuery: string; +}) { + return
ProgramMenu
; +} diff --git a/src/app/submission/components/Search.tsx b/src/app/submission/components/Search.tsx new file mode 100644 index 00000000..7c9bfdc5 --- /dev/null +++ b/src/app/submission/components/Search.tsx @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of + * the GNU Affero General Public License v3.0. You should have received a copy of the + * GNU Affero General Public License along with this program. + * If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +'use client'; + +export default function Search({ query, onChange }: { query: string; onChange: any }) { + return
Search
; +} diff --git a/src/app/submission/components/Sidemenu.tsx b/src/app/submission/components/Sidemenu.tsx new file mode 100644 index 00000000..4de939d0 --- /dev/null +++ b/src/app/submission/components/Sidemenu.tsx @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of + * the GNU Affero General Public License v3.0. You should have received a copy of the + * GNU Affero General Public License along with this program. + * If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +'use client'; + +export default function SideMenu() { + return
SideMenu
; +} diff --git a/src/app/submission/components/TitleBar.tsx b/src/app/submission/components/TitleBar.tsx new file mode 100644 index 00000000..f4df56f7 --- /dev/null +++ b/src/app/submission/components/TitleBar.tsx @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of + * the GNU Affero General Public License v3.0. You should have received a copy of the + * GNU Affero General Public License along with this program. + * If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +'use client'; + +import { css } from '@/lib/emotion'; +import { TitleBar as TitleBarComp } from '@icgc-argo/uikit'; + +export default function TitleBar() { + return ( +
+ + <>All Programs + +
+ future work +
+ +
+ future work +
+
+ ); +} diff --git a/src/app/submission/layout.tsx b/src/app/submission/layout.tsx new file mode 100644 index 00000000..1b336ef6 --- /dev/null +++ b/src/app/submission/layout.tsx @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of + * the GNU Affero General Public License v3.0. You should have received a copy of the + * GNU Affero General Public License along with this program. + * If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +'use client'; + +import { css, useTheme } from '@/lib/emotion'; +import { ReactNode } from 'react'; +import SideMenu from './components/Sidemenu'; +import TitleBar from './components/TitleBar'; + +export default function SubmissionLayout({ children }: { children: ReactNode }) { + const theme = useTheme(); + + return ( +
+ +
+ +
div { + background: white; + } + `} + > + {children} +
+
+
+ ); +} diff --git a/src/app/submission/page.tsx b/src/app/submission/page.tsx new file mode 100644 index 00000000..4461dede --- /dev/null +++ b/src/app/submission/page.tsx @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of + * the GNU Affero General Public License v3.0. You should have received a copy of the + * GNU Affero General Public License along with this program. + * If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +'use client'; + +import ProgramList from './components/ProgramList'; + +export default function Submission() { + return ; +} diff --git a/src/app/submission/tableConfig.tsx b/src/app/submission/tableConfig.tsx new file mode 100644 index 00000000..78b42ccf --- /dev/null +++ b/src/app/submission/tableConfig.tsx @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 The Ontario Institute for Cancer Research. All rights reserved + * + * This program and the accompanying materials are made available under the terms of + * the GNU Affero General Public License v3.0. You should have received a copy of the + * GNU Affero General Public License along with this program. + * If not, see . + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { css } from '@/lib/emotion'; +import { ColumnDef, PercentageBar } from '@icgc-argo/uikit'; +import { get } from 'lodash'; +import Link from 'next/link'; +import { ArgoMembershipKey, ProgramsData } from './components/ProgramList'; + +const MembershipDisplayName: { [key in ArgoMembershipKey]: string } = { + FULL: 'FULL', + ASSOCIATE: 'ASSOCIATE', +}; + +export const columns: ColumnDef[] = [ + { + header: 'Short Name', + accessorKey: 'shortName', + cell: ({ row: { original } }) => { + const shortName = original.shortName; + return ( +
+ {shortName} +
+ ); + }, + }, + { + header: 'Program Name', + accessorKey: 'name', + cell: ({ row: { original } }) =>
{original.name}
, + }, + { + header: 'Cancer Types', + accessorKey: 'cancerTypes', + cell: ({ row: { original } }) => ( +
+ {original.cancerTypes.map((cancerType, i) => ( +
+ {cancerType} + {i < original.cancerTypes.length - 1 && ','} +
+ ))} +
+ ), + }, + { + header: 'Countries', + accessorKey: 'countries', + cell: ({ row: { original } }) => { + const list = original.countries || []; + return ( +
+ {list.map((country, i) => ( +
+ {country} + {i < list.length - 1 && ','} +
+ ))} +
+ ); + }, + }, + { + header: 'Membership', + accessorKey: 'membershipType', + cell: ({ row: { original } }) => ( +
{original.membershipType ? MembershipDisplayName[original.membershipType] : ''}
+ ), + }, + { + header: 'Administrators', + accessorKey: 'administrators', + cell: ({ row: { original } }) => { + const adminLinks = get(original, 'administrators', []).map((admin, idx) => ( + + {admin.firstName + ' ' + admin.lastName} + {idx != original.administrators.length - 1 && ','} + + )); + + return
{adminLinks}
; + }, + }, + { + header: 'Donor Status', + accessorKey: 'donorPercentage', + size: 200, + cell: ({ row: { original } }) => ( +
+ +
+ ), + }, +]; diff --git a/src/global/constants.ts b/src/global/constants.ts index 895574f9..fa4d37c6 100644 --- a/src/global/constants.ts +++ b/src/global/constants.ts @@ -18,3 +18,4 @@ */ export const EGO_JWT_KEY = 'EGO_JWT'; +export const LOGIN_NONCE = 'LOGIN_NONCE'; diff --git a/src/global/utils/auth.tsx b/src/global/utils/auth.tsx index 4e08acc9..290326c2 100644 --- a/src/global/utils/auth.tsx +++ b/src/global/utils/auth.tsx @@ -18,34 +18,37 @@ */ 'use client'; +import Header from '@/app/components/Header'; +import { DnaLoader } from '@icgc-argo/uikit'; +import Cookies from 'js-cookie'; +import { usePathname, useRouter } from 'next/navigation'; import { - createContext, Dispatch, ReactNode, SetStateAction, Suspense, + createContext, useContext, - useEffect, useState, } from 'react'; -import Cookies from 'js-cookie'; -import { usePathname } from 'next/navigation'; -import Header from '@/app/components/Header'; -import { DnaLoader } from '@icgc-argo/uikit'; -import { EGO_JWT_KEY } from '../constants'; +import { EGO_JWT_KEY, LOGIN_NONCE } from '../constants'; type AuthContextValue = { egoJwt: string; setEgoJwt: Dispatch>; - loggingIn: boolean; - setLoggingIn: Dispatch>; + authLoading: boolean; + setAuthLoading: Dispatch>; + logIn: (newToken: string) => void; + logOut: () => void; }; const AuthContext = createContext({ egoJwt: '', setEgoJwt: () => '', - loggingIn: false, - setLoggingIn: () => false, + authLoading: false, + setAuthLoading: () => false, + logIn: () => undefined, + logOut: () => undefined, }); export const getStoredToken = () => Cookies.get(EGO_JWT_KEY); @@ -54,18 +57,30 @@ export const storeToken = (egoToken: string) => { Cookies.set(EGO_JWT_KEY, egoToken); }; -export const logOut = () => { - Cookies.remove(EGO_JWT_KEY); -}; - export function AuthProvider({ children }: { children: ReactNode }) { const storedToken = getStoredToken(); const [egoJwt, setEgoJwt] = useState(storedToken || ''); + const router = useRouter(); const path = usePathname(); - const initLoginState = path === '/logging-in' && !egoJwt.length ? true : false; - const [loggingIn, setLoggingIn] = useState(initLoginState); + const loginStateOnPageLoad = path === '/logging-in' && !egoJwt.length; + const [authLoading, setAuthLoading] = useState(loginStateOnPageLoad); + + const logIn = (newToken: string) => { + storeToken(newToken); + setEgoJwt(newToken); + setAuthLoading(false); + }; + + const logOut = () => { + setAuthLoading(true); + setEgoJwt(''); + Cookies.remove(EGO_JWT_KEY); + Cookies.remove(LOGIN_NONCE); + router.push('/'); + setAuthLoading(false); + }; - const value: AuthContextValue = { egoJwt, setEgoJwt, loggingIn, setLoggingIn }; + const value: AuthContextValue = { egoJwt, setEgoJwt, authLoading, setAuthLoading, logIn, logOut }; return (