From c55b22101f3be2b8f172841dc3964dcc18825e47 Mon Sep 17 00:00:00 2001 From: John Kaster Date: Thu, 28 Oct 2021 15:14:27 -0700 Subject: [PATCH] feat: markdown, link click support, and project view for hackathon projects (#877) ## Added - `ProjectView` - `ProjectViewScene` - Project form - **Preview** of the project - Descriptions for project type selector - Markdown template for description to aid in complete new project submission ## Changed - "Contestant" project toggle to "Submit this project for judging?" - to Outline versions of icons - "View Project" on judging action list ## Removed - "More information" from project list, editing form, and source code ## Screenshots ### Updated form ![image](https://user-images.githubusercontent.com/6099714/139144569-653be827-8b0f-4ce6-8fe6-a7bf2e7abd65.png) ### Preview project on form (The `John [Object]` is from bad data in my spreadsheet. Ignore) ![image](https://user-images.githubusercontent.com/6099714/139144709-01aff55c-eb18-4633-ac6a-adc8abf18db4.png) ### View project ![image](https://user-images.githubusercontent.com/6099714/139144887-c8b1cc40-7150-42ce-a774-dadaf1b596ee.png) ### Judging #### View project menu ![image](https://user-images.githubusercontent.com/6099714/139342825-eb58e100-b220-434a-8385-3710b9ec93f7.png) #### View project from judging list ![image](https://user-images.githubusercontent.com/6099714/139342706-a58d0528-cee7-489c-ace2-1d22f93ec9b7.png) --- .../hackathon/src/components/Header/index.ts | 2 +- .../hackathon/src/components/Loading/index.ts | 2 +- .../ProjectViewDialog.tsx} | 46 ++- .../index.ts | 2 +- .../src/components/Scroller/index.ts | 2 +- .../src/components/SideNav/SideNav.tsx | 6 +- .../hackathon/src/components/SideNav/index.ts | 2 +- .../hackathon/src/data/projects/actions.ts | 17 -- .../hackathon/src/data/projects/reducer.ts | 9 - packages/hackathon/src/data/projects/sagas.ts | 9 +- .../hackathon/src/data/projects/selectors.ts | 5 - packages/hackathon/src/models/Judgings.ts | 12 +- packages/hackathon/src/routes/AppRouter.tsx | 8 + packages/hackathon/src/routes/index.ts | 2 +- .../hackathon/src/scenes/AdminScene/index.ts | 2 +- .../hackathon/src/scenes/HomeScene/index.ts | 2 +- .../JudgingEditorScene/components/index.ts | 2 +- .../src/scenes/JudgingEditorScene/index.ts | 2 +- .../JudgingScene/components/JudgingList.tsx | 61 ++-- .../scenes/JudgingScene/components/index.ts | 2 +- .../src/scenes/JudgingScene/index.ts | 2 +- .../src/scenes/NotFoundScene/index.ts | 2 +- .../components/ProjectForm.tsx | 261 ++++++++++-------- .../ProjectEditorScene/components/index.ts | 3 +- .../src/scenes/ProjectEditorScene/index.ts | 2 +- .../ProjectViewScene/ProjectViewScene.tsx | 99 +++++++ .../components/ProjectView.tsx | 76 +++++ .../ProjectViewScene/components/index.ts | 27 ++ .../src/scenes/ProjectViewScene/index.ts | 26 ++ .../scenes/ProjectsScene/ProjectsScene.tsx | 14 +- .../ProjectsScene/components/ProjectList.tsx | 49 ++-- .../scenes/ProjectsScene/components/index.ts | 2 +- .../src/scenes/ProjectsScene/index.ts | 2 +- .../src/scenes/ResourceScene/index.ts | 2 +- .../src/scenes/UsersScene/components/index.ts | 2 +- .../hackathon/src/scenes/UsersScene/index.ts | 2 +- packages/hackathon/src/scenes/index.ts | 19 +- 37 files changed, 515 insertions(+), 270 deletions(-) rename packages/hackathon/src/components/{MoreInfoDialog/MoreInfoDialog.tsx => ProjectViewDialog/ProjectViewDialog.tsx} (55%) rename packages/hackathon/src/components/{MoreInfoDialog => ProjectViewDialog}/index.ts (95%) create mode 100644 packages/hackathon/src/scenes/ProjectViewScene/ProjectViewScene.tsx create mode 100644 packages/hackathon/src/scenes/ProjectViewScene/components/ProjectView.tsx create mode 100644 packages/hackathon/src/scenes/ProjectViewScene/components/index.ts create mode 100644 packages/hackathon/src/scenes/ProjectViewScene/index.ts diff --git a/packages/hackathon/src/components/Header/index.ts b/packages/hackathon/src/components/Header/index.ts index 51eb7631c..72b5dfba8 100644 --- a/packages/hackathon/src/components/Header/index.ts +++ b/packages/hackathon/src/components/Header/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { Header } from './Header' +export * from './Header' diff --git a/packages/hackathon/src/components/Loading/index.ts b/packages/hackathon/src/components/Loading/index.ts index 63b69b4b3..fe36eccc7 100644 --- a/packages/hackathon/src/components/Loading/index.ts +++ b/packages/hackathon/src/components/Loading/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { Loading } from './Loading' +export * from './Loading' diff --git a/packages/hackathon/src/components/MoreInfoDialog/MoreInfoDialog.tsx b/packages/hackathon/src/components/ProjectViewDialog/ProjectViewDialog.tsx similarity index 55% rename from packages/hackathon/src/components/MoreInfoDialog/MoreInfoDialog.tsx rename to packages/hackathon/src/components/ProjectViewDialog/ProjectViewDialog.tsx index 50423fa99..d2f392389 100644 --- a/packages/hackathon/src/components/MoreInfoDialog/MoreInfoDialog.tsx +++ b/packages/hackathon/src/components/ProjectViewDialog/ProjectViewDialog.tsx @@ -25,42 +25,28 @@ */ import type { FC } from 'react' import React from 'react' -import { - Dialog, - DialogHeader, - DialogContent, - Paragraph, - SpaceVertical, - TextArea, -} from '@looker/components' -import { useSelector, useDispatch } from 'react-redux' -import { setMoreInfo } from '../../data/projects/actions' -import { getMoreInfoState } from '../../data/projects/selectors' +import { Dialog, DialogHeader, DialogContent } from '@looker/components' +import { ProjectView } from '../../scenes/ProjectViewScene/components' +import type { IProjectProps } from '../../models' -interface MoreInfoDialogProps {} - -export const MoreInfoDialog: FC = () => { - const dispatch = useDispatch() - const moreInfoProject = useSelector(getMoreInfoState) +interface ProjectViewDialogProps { + project?: IProjectProps + closer: () => void +} - const closeMoreInfo = () => { - dispatch(setMoreInfo()) +export const ProjectViewDialog: FC = ({ + project, + closer, +}) => { + const closeDialog = () => { + closer() } return ( - - {moreInfoProject?.title} + + Judging {project?.title} - - - Copy the link below and paste into a new browser window to see - additional information about the project - - - + {!!project && } ) diff --git a/packages/hackathon/src/components/MoreInfoDialog/index.ts b/packages/hackathon/src/components/ProjectViewDialog/index.ts similarity index 95% rename from packages/hackathon/src/components/MoreInfoDialog/index.ts rename to packages/hackathon/src/components/ProjectViewDialog/index.ts index 5c92fa1f7..2960142ca 100644 --- a/packages/hackathon/src/components/MoreInfoDialog/index.ts +++ b/packages/hackathon/src/components/ProjectViewDialog/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { MoreInfoDialog } from './MoreInfoDialog' +export * from './ProjectViewDialog' diff --git a/packages/hackathon/src/components/Scroller/index.ts b/packages/hackathon/src/components/Scroller/index.ts index 07517cb7c..0bf920e17 100644 --- a/packages/hackathon/src/components/Scroller/index.ts +++ b/packages/hackathon/src/components/Scroller/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { Scroller } from './Scroller' +export * from './Scroller' diff --git a/packages/hackathon/src/components/SideNav/SideNav.tsx b/packages/hackathon/src/components/SideNav/SideNav.tsx index 51430c297..fc505946b 100644 --- a/packages/hackathon/src/components/SideNav/SideNav.tsx +++ b/packages/hackathon/src/components/SideNav/SideNav.tsx @@ -26,7 +26,7 @@ import type { FC } from 'react' import React from 'react' import styled from 'styled-components' -import { Box, MenuList, MenuItem } from '@looker/components' +import { Box2, MenuList, MenuItem } from '@looker/components' import { Beaker } from '@looker/icons' import { Map } from '@styled-icons/material/Map' import { Settings } from '@styled-icons/material/Settings' @@ -41,7 +41,7 @@ export interface SideNavProps { } export const SideNav: FC = ({ authorizedRoutes }) => ( - + {authorizedRoutes.includes(Routes.HOME) && ( }> @@ -74,7 +74,7 @@ export const SideNav: FC = ({ authorizedRoutes }) => ( )} - + ) const Link = styled(NavLink)` diff --git a/packages/hackathon/src/components/SideNav/index.ts b/packages/hackathon/src/components/SideNav/index.ts index 75ab69220..ac0ccd251 100644 --- a/packages/hackathon/src/components/SideNav/index.ts +++ b/packages/hackathon/src/components/SideNav/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { SideNav } from './SideNav' +export * from './SideNav' diff --git a/packages/hackathon/src/data/projects/actions.ts b/packages/hackathon/src/data/projects/actions.ts index 2cbbfdba6..f6a2e95b1 100644 --- a/packages/hackathon/src/data/projects/actions.ts +++ b/packages/hackathon/src/data/projects/actions.ts @@ -137,14 +137,6 @@ export interface LockProjectAction { } } -export interface SetMoreInfoAction { - type: Actions.SET_MORE_INFO - payload?: { - title: string - moreInfo: string - } -} - export type ProjectAction = | AllProjectsRequestAction | AllProjectsResponseAction @@ -161,7 +153,6 @@ export type ProjectAction = | LockProjectAction | ChangeMembershipAction | UpdateProjectsPageNumAction - | SetMoreInfoAction export const allProjectsRequest = (): AllProjectsRequestAction => ({ type: Actions.ALL_PROJECTS_REQUEST, @@ -278,11 +269,3 @@ export const changeMembership = ( leave, }, }) - -export const setMoreInfo = ( - title?: string, - moreInfo?: string -): SetMoreInfoAction => ({ - type: Actions.SET_MORE_INFO, - payload: moreInfo && title ? { title, moreInfo } : undefined, -}) diff --git a/packages/hackathon/src/data/projects/reducer.ts b/packages/hackathon/src/data/projects/reducer.ts index 641b6b2bb..4cb97ebc8 100644 --- a/packages/hackathon/src/data/projects/reducer.ts +++ b/packages/hackathon/src/data/projects/reducer.ts @@ -38,10 +38,6 @@ export interface ProjectsState { validationMessages?: ValidationMessages projectUpdated?: boolean projectLoaded: boolean - moreInfo?: { - title: string - moreInfo: string - } } const defaultState: Readonly = Object.freeze({ @@ -123,11 +119,6 @@ export const projectsReducer = ( isProjectMember: action.payload.isProjectMember, projectUpdated: true, } - case Actions.SET_MORE_INFO: - return { - ...state, - moreInfo: action.payload, - } default: return state } diff --git a/packages/hackathon/src/data/projects/sagas.ts b/packages/hackathon/src/data/projects/sagas.ts index d430757d9..7a883c7f4 100644 --- a/packages/hackathon/src/data/projects/sagas.ts +++ b/packages/hackathon/src/data/projects/sagas.ts @@ -50,7 +50,14 @@ import { getCurrentProjectsState, getIsProjectMemberState } from './selectors' const createNewProject = (): IProjectProps => { const newProject: unknown = { title: '', - description: '', + description: ` + +Team name: **My fabulous team** +- Pre-recorded [demo video link](https://youtube.com) (preferably youtube) +- Working [demo](https://looker.com) (optional). Provide any relevant start-up instructions for someone to run the demo. +- Links to any other [supporting resources](https://docs.google.com) (slides, images, etc.) (preferably google slides and imgur) +- Add your pictures/screenshots of your team hacking to the [Hack@Home 2021 shared folder](https://tbd). Create your own team folder inside it if you'd like! +`, project_type: 'Open', contestant: false, locked: false, diff --git a/packages/hackathon/src/data/projects/selectors.ts b/packages/hackathon/src/data/projects/selectors.ts index 457d09c5e..15d1be9d4 100644 --- a/packages/hackathon/src/data/projects/selectors.ts +++ b/packages/hackathon/src/data/projects/selectors.ts @@ -40,11 +40,6 @@ export const getProjectsLoadedState = (state: RootState): boolean => export const getProjectsPageNumState = (state: RootState): number => state.projectsState.currentPageNum -export const getMoreInfoState = ( - state: RootState -): { title: string; moreInfo: string } | undefined => - state.projectsState.moreInfo - export const getProjectState = (state: RootState): IProjectProps | undefined => state.projectsState.currentProject diff --git a/packages/hackathon/src/models/Judgings.ts b/packages/hackathon/src/models/Judgings.ts index a01c1b4fd..536b8f909 100644 --- a/packages/hackathon/src/models/Judgings.ts +++ b/packages/hackathon/src/models/Judgings.ts @@ -47,7 +47,9 @@ export interface IJudgingProps extends IRowModelProps { notes: string $title: string $description: string - $more_info: string + $project_type: string + $contestant: boolean + $technologies: string[] $judge_name: string $members: string[] } @@ -72,8 +74,10 @@ export class Judging extends SheetRow { notes = '' $title = '' $description = '' - $more_info = '' $judge_name = '' + $project_type = '' + $contestant = false + $technologies: string[] = [] $members: string[] = [] constructor(values?: any) { @@ -95,10 +99,12 @@ export class Judging extends SheetRow { } const p = data.projects?.find(this.project_id) as Project if (p) { + this.$project_type = p.project_type + this.$contestant = p.contestant + this.$technologies = p.technologies this.$title = p.title this.$description = p.description this.$members = p.$members - this.$more_info = p.more_info } } diff --git a/packages/hackathon/src/routes/AppRouter.tsx b/packages/hackathon/src/routes/AppRouter.tsx index c19738dd4..ad5e62932 100644 --- a/packages/hackathon/src/routes/AppRouter.tsx +++ b/packages/hackathon/src/routes/AppRouter.tsx @@ -38,12 +38,14 @@ import { ProjectEditorScene, ResourceScene, } from '../scenes' +import { ProjectViewScene } from '../scenes/ProjectViewScene' export enum Routes { HOME = '/home', ADMIN = '/admin', JUDGING = '/judging', EDIT_JUDGING = '/judging/:id', PROJECTS = '/projects', + VIEW_PROJECT = '/projectview/:id', CREATE_PROJECT = '/projects/new', EDIT_PROJECT = '/projects/:id', USERS = '/users', @@ -65,6 +67,7 @@ export const getAuthorizedRoutes = ( if (hacker) { if (currentHackathon) { authorizedRoutes.push(Routes.PROJECTS) + authorizedRoutes.push(Routes.VIEW_PROJECT) authorizedRoutes.push(Routes.CREATE_PROJECT) authorizedRoutes.push(Routes.EDIT_PROJECT) if (hacker.canAdmin || hacker.canJudge || hacker.canStaff) { @@ -132,6 +135,11 @@ export const AppRouter: FC = ({ authorizedRoutes, hacker }) => ( )} + {authorizedRoutes.includes(Routes.VIEW_PROJECT) && ( + + + + )} {authorizedRoutes.includes(Routes.USERS) && ( diff --git a/packages/hackathon/src/routes/index.ts b/packages/hackathon/src/routes/index.ts index 75df11404..934e03e88 100644 --- a/packages/hackathon/src/routes/index.ts +++ b/packages/hackathon/src/routes/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { AppRouter, getAuthorizedRoutes } from './AppRouter' +export * from './AppRouter' diff --git a/packages/hackathon/src/scenes/AdminScene/index.ts b/packages/hackathon/src/scenes/AdminScene/index.ts index f7601df22..aac86a918 100644 --- a/packages/hackathon/src/scenes/AdminScene/index.ts +++ b/packages/hackathon/src/scenes/AdminScene/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { AdminScene } from './AdminScene' +export * from './AdminScene' diff --git a/packages/hackathon/src/scenes/HomeScene/index.ts b/packages/hackathon/src/scenes/HomeScene/index.ts index 334fc04d3..886b0e495 100644 --- a/packages/hackathon/src/scenes/HomeScene/index.ts +++ b/packages/hackathon/src/scenes/HomeScene/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { HomeScene } from './HomeScene' +export * from './HomeScene' diff --git a/packages/hackathon/src/scenes/JudgingEditorScene/components/index.ts b/packages/hackathon/src/scenes/JudgingEditorScene/components/index.ts index 9dbe54344..09b945688 100644 --- a/packages/hackathon/src/scenes/JudgingEditorScene/components/index.ts +++ b/packages/hackathon/src/scenes/JudgingEditorScene/components/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { JudgingForm } from './JudgingForm' +export * from './JudgingForm' diff --git a/packages/hackathon/src/scenes/JudgingEditorScene/index.ts b/packages/hackathon/src/scenes/JudgingEditorScene/index.ts index a3a2a12c4..b9f30c223 100644 --- a/packages/hackathon/src/scenes/JudgingEditorScene/index.ts +++ b/packages/hackathon/src/scenes/JudgingEditorScene/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { JudgingEditorScene } from './JudgingEditorScene' +export * from './JudgingEditorScene' diff --git a/packages/hackathon/src/scenes/JudgingScene/components/JudgingList.tsx b/packages/hackathon/src/scenes/JudgingScene/components/JudgingList.tsx index 43300dd8f..6ec3bf919 100644 --- a/packages/hackathon/src/scenes/JudgingScene/components/JudgingList.tsx +++ b/packages/hackathon/src/scenes/JudgingScene/components/JudgingList.tsx @@ -24,7 +24,7 @@ */ import type { FC } from 'react' -import React, { useEffect } from 'react' +import React, { useEffect, useState } from 'react' import { DataTable, DataTableItem, @@ -32,12 +32,15 @@ import { DataTableCell, Pagination, } from '@looker/components' -import { Info } from '@styled-icons/material/Info' -import { Create } from '@styled-icons/material/Create' +import { TextSnippet } from '@styled-icons/material-outlined/TextSnippet' +import { Create } from '@styled-icons/material-outlined/Create' import { useSelector, useDispatch } from 'react-redux' import { useHistory } from 'react-router-dom' -import { MoreInfoDialog } from '../../../components/MoreInfoDialog' -import type { IJudgingProps } from '../../../models' +import type { + IHackerProps, + IJudgingProps, + IProjectProps, +} from '../../../models' import { sheetCell } from '../../../models' import { getHackerState, @@ -51,9 +54,26 @@ import { getJudgingsState, getJudgingsPageNumState, } from '../../../data/judgings/selectors' -import { setMoreInfo } from '../../../data/projects/actions' import { canDoJudgingAction } from '../../../utils' import { PAGE_SIZE } from '../../../constants' +import { ProjectViewDialog } from '../../../components/ProjectViewDialog' + +const asProject = ( + hacker: IHackerProps, + judging: IJudgingProps +): IProjectProps => { + return { + _id: 'projectviewdialog', + _row: 0, + _user_id: hacker.id, + title: judging.$title, + project_type: judging.$project_type, + technologies: judging.$technologies, + $members: judging.$members, + description: judging.$description, + contestant: judging.$contestant, + } as IProjectProps +} interface JudgingListProps {} @@ -64,6 +84,9 @@ export const JudgingList: FC = () => { const hacker = useSelector(getHackerState) const judgings = useSelector(getJudgingsState) const currentPage = useSelector(getJudgingsPageNumState) + const [currentProject, setCurrentProject] = useState< + IProjectProps | undefined + >(undefined) useEffect(() => { dispatch(getJudgingsRequest()) @@ -73,8 +96,12 @@ export const JudgingList: FC = () => { dispatch(updateJudgingsPageNum(pageNum)) } - const openMoreInfo = ({ $title, $more_info }: IJudgingProps) => { - dispatch(setMoreInfo($title, $more_info)) + const viewProject = (judging: IJudgingProps) => { + setCurrentProject(asProject(hacker, judging)) + } + + const hideProject = () => { + setCurrentProject(undefined) } const showJudging = (judgingId: string) => { @@ -86,14 +113,12 @@ export const JudgingList: FC = () => { const actions = (judging: IJudgingProps) => { return ( <> - {judging.$more_info && judging.$more_info !== '\0' && ( - } - > - More Information - - )} + } + > + View Project + } @@ -101,7 +126,7 @@ export const JudgingList: FC = () => { > {canDoJudgingAction(hacker, judging) ? 'Update Judging' - : 'View Juding'} + : 'View Judging'} ) @@ -132,7 +157,7 @@ export const JudgingList: FC = () => { pages={totalPages} onChange={updatePage} /> - + ) } diff --git a/packages/hackathon/src/scenes/JudgingScene/components/index.ts b/packages/hackathon/src/scenes/JudgingScene/components/index.ts index c98d36cc0..b8504a4f0 100644 --- a/packages/hackathon/src/scenes/JudgingScene/components/index.ts +++ b/packages/hackathon/src/scenes/JudgingScene/components/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { JudgingList } from './JudgingList' +export * from './JudgingList' diff --git a/packages/hackathon/src/scenes/JudgingScene/index.ts b/packages/hackathon/src/scenes/JudgingScene/index.ts index 2f7b0dd11..e88e5c731 100644 --- a/packages/hackathon/src/scenes/JudgingScene/index.ts +++ b/packages/hackathon/src/scenes/JudgingScene/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { JudgingScene } from './JudgingScene' +export * from './JudgingScene' diff --git a/packages/hackathon/src/scenes/NotFoundScene/index.ts b/packages/hackathon/src/scenes/NotFoundScene/index.ts index 36ab0043b..33a2dd6d9 100644 --- a/packages/hackathon/src/scenes/NotFoundScene/index.ts +++ b/packages/hackathon/src/scenes/NotFoundScene/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { NotFoundScene } from './NotFoundScene' +export * from './NotFoundScene' diff --git a/packages/hackathon/src/scenes/ProjectEditorScene/components/ProjectForm.tsx b/packages/hackathon/src/scenes/ProjectEditorScene/components/ProjectForm.tsx index 91ca9f348..486a8046f 100644 --- a/packages/hackathon/src/scenes/ProjectEditorScene/components/ProjectForm.tsx +++ b/packages/hackathon/src/scenes/ProjectEditorScene/components/ProjectForm.tsx @@ -48,6 +48,9 @@ import { Button, ButtonOutline, Space, + Tab2, + Tabs2, + SpaceVertical, } from '@looker/components' import { useDispatch, useSelector } from 'react-redux' import { useHistory, useRouteMatch } from 'react-router-dom' @@ -76,7 +79,8 @@ import { import { allHackersRequest } from '../../../data/hackers/actions' import { getJudgesState } from '../../../data/hackers/selectors' import { canUpdateProject, canLockProject } from '../../../utils' -import { Routes } from '../../../routes/AppRouter' +import { Routes } from '../../../routes' +import { ProjectView } from '../../ProjectViewScene/components' interface ProjectFormProps {} @@ -122,7 +126,14 @@ export const ProjectForm: FC = () => { dispatch(actionMessage('Invalid project', 'critical')) } } - }, [project, isProjectLoaded, hackerRegistrationId]) + }, [ + project, + isProjectLoaded, + hackerRegistrationId, + projectIdOrNew, + dispatch, + history, + ]) const handleSubmit = (e: FormEvent) => { e.preventDefault() @@ -148,123 +159,135 @@ export const ProjectForm: FC = () => { if (!project) return <> - // TODO move this to the sage and pull data out of rudux + // TODO move this to the saga and pull data out of redux const canUpdate = canUpdateProject(hacker, project, projectIdOrNew === 'new') const canLock = canLockProject(hacker) && projectIdOrNew !== 'new' return ( -
-
- { - dispatch(updateProjectData({ ...project, title: e.target.value })) - }} - /> - { - dispatch( - updateProjectData({ ...project, description: e.target.value }) - ) - }} - /> - { - dispatch(updateProjectData({ ...project, project_type: value })) - }} - /> - { - dispatch( - updateProjectData({ ...project, contestant: e.target.checked }) - ) - }} - on={project.contestant} - /> - ({ - value: technology._id, - }))} - isFilterable - placeholder="Type values or select from the list" - values={project.technologies} - onChange={(values: string[] = []) => { - dispatch(updateProjectData({ ...project, technologies: values })) - }} - /> - { - dispatch( - updateProjectData({ ...project, more_info: e.target.value }) - ) - }} - /> - {projectIdOrNew !== 'new' && ( - - )} -
- {projectIdOrNew !== 'new' && ( - ({ - value: judge.name, - }))} - isFilterable - placeholder="Type values or select from the list" - values={[...project.$judges]} - onChange={(values: string[] = []) => { - dispatch( - updateProjectData({ - ...project, - $judges: values, - }) - ) - }} - /> - )} - + + + + +
+ { + dispatch( + updateProjectData({ ...project, title: e.target.value }) + ) + }} + /> + { + dispatch( + updateProjectData({ + ...project, + description: e.target.value, + }) + ) + }} + /> + { + dispatch( + updateProjectData({ ...project, project_type: value }) + ) + }} + /> + { + dispatch( + updateProjectData({ + ...project, + contestant: e.target.checked, + }) + ) + }} + on={project.contestant} + /> + ({ + value: technology._id, + }))} + isFilterable + placeholder="Type values or select from the list" + values={project.technologies} + onChange={(values: string[] = []) => { + dispatch( + updateProjectData({ ...project, technologies: values }) + ) + }} + /> + {projectIdOrNew !== 'new' && ( + + )} +
+ {projectIdOrNew !== 'new' && ( + ({ + value: judge.name, + }))} + isFilterable + placeholder="Type values or select from the list" + values={[...project.$judges]} + onChange={(values: string[] = []) => { + dispatch( + updateProjectData({ + ...project, + $judges: values, + }) + ) + }} + /> + )} + +
+ + + +
+ = () => { > Return to projects - @@ -295,6 +322,6 @@ export const ProjectForm: FC = () => { )} - +
) } diff --git a/packages/hackathon/src/scenes/ProjectEditorScene/components/index.ts b/packages/hackathon/src/scenes/ProjectEditorScene/components/index.ts index 8ca2ce7a9..61b1bc08f 100644 --- a/packages/hackathon/src/scenes/ProjectEditorScene/components/index.ts +++ b/packages/hackathon/src/scenes/ProjectEditorScene/components/index.ts @@ -23,4 +23,5 @@ SOFTWARE. */ -export { ProjectForm } from './ProjectForm' + +export * from './ProjectForm' diff --git a/packages/hackathon/src/scenes/ProjectEditorScene/index.ts b/packages/hackathon/src/scenes/ProjectEditorScene/index.ts index c4f0cb58d..f0aca7d0c 100644 --- a/packages/hackathon/src/scenes/ProjectEditorScene/index.ts +++ b/packages/hackathon/src/scenes/ProjectEditorScene/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { ProjectEditorScene } from './ProjectEditorScene' +export * from './ProjectEditorScene' diff --git a/packages/hackathon/src/scenes/ProjectViewScene/ProjectViewScene.tsx b/packages/hackathon/src/scenes/ProjectViewScene/ProjectViewScene.tsx new file mode 100644 index 000000000..a27afcb34 --- /dev/null +++ b/packages/hackathon/src/scenes/ProjectViewScene/ProjectViewScene.tsx @@ -0,0 +1,99 @@ +/* + + MIT License + + Copyright (c) 2021 Looker Data Sciences, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + */ +import type { FC } from 'react' +import { useDispatch, useSelector } from 'react-redux' +import { useHistory, useRouteMatch } from 'react-router-dom' +import React, { useEffect } from 'react' +import { SpaceVertical, Space, Button } from '@looker/components' +import { isLoadingState } from '../../data/common/selectors' +import { + getProjectLoadedState, + getProjectState, +} from '../../data/projects/selectors' +import { getProjectRequest } from '../../data/projects/actions' +import { Routes } from '../../routes' +import { Loading } from '../../components' +import { actionMessage } from '../../data/common/actions' +import { ProjectView } from './components' + +export const ProjectViewScene: FC = () => { + const dispatch = useDispatch() + const history = useHistory() + const match = useRouteMatch<{ projectId: string }>('/projectview/:projectId') + const isLoading = useSelector(isLoadingState) + const projectId = match?.params?.projectId + const isProjectLoaded = useSelector(getProjectLoadedState) + const project = useSelector(getProjectState) + + const invalidProject = () => + dispatch(actionMessage('Invalid project', 'critical')) + + useEffect(() => { + if (project) { + if (projectId === 'new') { + invalidProject() + } + } else { + if (isProjectLoaded) { + invalidProject() + } + } + }, [dispatch, history, projectId, project, isProjectLoaded]) + + const handleCancel = () => { + history.push(Routes.PROJECTS) + } + + useEffect(() => { + if (projectId && !project) { + if (projectId === 'new') { + invalidProject() + } else { + dispatch(getProjectRequest(projectId === 'new' ? undefined : projectId)) + } + } + }, [dispatch, projectId, project]) + + return ( + + + {project ? ( + + ) : ( + + )} + + + + + + ) +} diff --git a/packages/hackathon/src/scenes/ProjectViewScene/components/ProjectView.tsx b/packages/hackathon/src/scenes/ProjectViewScene/components/ProjectView.tsx new file mode 100644 index 000000000..80bc7171e --- /dev/null +++ b/packages/hackathon/src/scenes/ProjectViewScene/components/ProjectView.tsx @@ -0,0 +1,76 @@ +/* + + MIT License + + Copyright (c) 2021 Looker Data Sciences, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + */ + +import type { FC } from 'react' +import React from 'react' +import { useSelector } from 'react-redux' +import type { IProjectProps, ITechnologyProps } from '../../../models' +import { ExtMarkdown } from '../../../components' +import { getTechnologies } from '../../../data/hack_session/selectors' + +interface ProjectViewProps { + project: IProjectProps +} + +const techDescriptions = (ids: string[], technologies?: ITechnologyProps[]) => { + try { + return technologies + ?.filter((t) => ids.includes(t._id)) + .map((t) => t.description) + .join(', ') + } catch { + // avoid sheet data errors + return ids.join(', ') + } +} + +const getMembers = (team: string[]) => { + try { + return team.join(', ') || 'Nobody!' + } catch { + // avoid sheet data errors + return 'Error retrieving team members' + } +} + +export const ProjectView: FC = ({ project }) => { + const availableTechnologies = useSelector(getTechnologies) + + const tech = techDescriptions(project.technologies, availableTechnologies) + const members = getMembers(project.$members) + const view = `# ${project.title} +by ${members} + +${project.description} + +**Uses**: ${tech} + +**Project type**: ${project.project_type} + +**Contestant**: ${project.contestant ? 'Yes' : 'No'} +` + return +} diff --git a/packages/hackathon/src/scenes/ProjectViewScene/components/index.ts b/packages/hackathon/src/scenes/ProjectViewScene/components/index.ts new file mode 100644 index 000000000..5e2acb461 --- /dev/null +++ b/packages/hackathon/src/scenes/ProjectViewScene/components/index.ts @@ -0,0 +1,27 @@ +/* + + MIT License + + Copyright (c) 2021 Looker Data Sciences, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + */ + +export * from './ProjectView' diff --git a/packages/hackathon/src/scenes/ProjectViewScene/index.ts b/packages/hackathon/src/scenes/ProjectViewScene/index.ts new file mode 100644 index 000000000..7b020817d --- /dev/null +++ b/packages/hackathon/src/scenes/ProjectViewScene/index.ts @@ -0,0 +1,26 @@ +/* + + MIT License + + Copyright (c) 2021 Looker Data Sciences, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + */ +export * from './ProjectViewScene' diff --git a/packages/hackathon/src/scenes/ProjectsScene/ProjectsScene.tsx b/packages/hackathon/src/scenes/ProjectsScene/ProjectsScene.tsx index dbcb96bce..79a60bc21 100644 --- a/packages/hackathon/src/scenes/ProjectsScene/ProjectsScene.tsx +++ b/packages/hackathon/src/scenes/ProjectsScene/ProjectsScene.tsx @@ -29,12 +29,12 @@ import React from 'react' import { useSelector, useDispatch } from 'react-redux' import { useHistory } from 'react-router-dom' import { Button, Space } from '@looker/components' -import { AddCircle } from '@styled-icons/material/AddCircle' -import { Create } from '@styled-icons/material/Create' -import { Lock } from '@styled-icons/material/Lock' +import { Add } from '@styled-icons/material-outlined/Add' +import { Create } from '@styled-icons/material-outlined/Create' +import { Lock } from '@styled-icons/material-outlined/Lock' import { lockProjects } from '../../data/projects/actions' import { isLoadingState } from '../../data/common/selectors' -import { Loading } from '../../components/Loading' +import { Loading } from '../../components' import { Routes } from '../../routes/AppRouter' import { getCurrentHackathonState, @@ -68,11 +68,7 @@ export const ProjectsScene: FC = () => { - <> diff --git a/packages/hackathon/src/scenes/ProjectsScene/components/ProjectList.tsx b/packages/hackathon/src/scenes/ProjectsScene/components/ProjectList.tsx index 619b2c249..f192c3071 100644 --- a/packages/hackathon/src/scenes/ProjectsScene/components/ProjectList.tsx +++ b/packages/hackathon/src/scenes/ProjectsScene/components/ProjectList.tsx @@ -34,15 +34,13 @@ import { Tooltip, Icon, } from '@looker/components' -import { ModelFile } from '@looker/icons' -import { Lock } from '@styled-icons/material/Lock' -import { Info } from '@styled-icons/material/Info' -import { Create } from '@styled-icons/material/Create' -import { Delete } from '@styled-icons/material/Delete' +import { TextSnippet } from '@styled-icons/material-outlined/TextSnippet' +import { Lock } from '@styled-icons/material-outlined/Lock' +import { Create } from '@styled-icons/material-outlined/Create' +import { Delete } from '@styled-icons/material-outlined/Delete' import { FactCheck } from '@styled-icons/material-outlined/FactCheck' import { useSelector, useDispatch } from 'react-redux' import { useHistory } from 'react-router-dom' -import { MoreInfoDialog } from '../../../components/MoreInfoDialog' import type { IProjectProps } from '../../../models' import { sheetCell } from '../../../models' import { @@ -55,7 +53,6 @@ import { deleteProject, currentProjectsRequest, updateProjectsPageNum, - setMoreInfo, } from '../../../data/projects/actions' import { getCurrentProjectsState, @@ -78,10 +75,6 @@ export const ProjectList: FC = () => { dispatch(deleteProject(project._id)) } - const openMoreInfo = ({ title, more_info }: IProjectProps) => { - dispatch(setMoreInfo(title, more_info)) - } - const lockCol = columns[0] lockCol.canSort = false lockCol.size = 'auto' @@ -105,20 +98,18 @@ export const ProjectList: FC = () => { }) } + const handleView = (projectId: string) => { + setTimeout(() => { + history.push(`/projectview/${projectId}`) + }) + } + const actions = (project: IProjectProps) => { const isLocked = project.locked return ( <> - {project.more_info && project.more_info !== '\0' && ( - } - > - More Information - - )} - {canDoProjectAction(hacker, project, 'update') ? ( + {canDoProjectAction(hacker, project, 'update') && ( : } @@ -126,15 +117,16 @@ export const ProjectList: FC = () => { > Update project - ) : ( - : } - itemRole="link" - > - View project - )} + + } + itemRole="link" + > + View project + + {canDoProjectAction(hacker, project, 'delete') && ( = () => { pages={totalPages} onChange={(pageNumber) => dispatch(updateProjectsPageNum(pageNumber))} /> - ) } diff --git a/packages/hackathon/src/scenes/ProjectsScene/components/index.ts b/packages/hackathon/src/scenes/ProjectsScene/components/index.ts index 3eebdd124..7513ad5b6 100644 --- a/packages/hackathon/src/scenes/ProjectsScene/components/index.ts +++ b/packages/hackathon/src/scenes/ProjectsScene/components/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { ProjectList } from './ProjectList' +export * from './ProjectList' diff --git a/packages/hackathon/src/scenes/ProjectsScene/index.ts b/packages/hackathon/src/scenes/ProjectsScene/index.ts index ce675621f..b56fea79d 100644 --- a/packages/hackathon/src/scenes/ProjectsScene/index.ts +++ b/packages/hackathon/src/scenes/ProjectsScene/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { ProjectsScene } from './ProjectsScene' +export * from './ProjectsScene' diff --git a/packages/hackathon/src/scenes/ResourceScene/index.ts b/packages/hackathon/src/scenes/ResourceScene/index.ts index ce5ef79c7..a5e287226 100644 --- a/packages/hackathon/src/scenes/ResourceScene/index.ts +++ b/packages/hackathon/src/scenes/ResourceScene/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { ResourceScene } from './ResourceScene' +export * from './ResourceScene' diff --git a/packages/hackathon/src/scenes/UsersScene/components/index.ts b/packages/hackathon/src/scenes/UsersScene/components/index.ts index 6d74b11ad..1c32723e5 100644 --- a/packages/hackathon/src/scenes/UsersScene/components/index.ts +++ b/packages/hackathon/src/scenes/UsersScene/components/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { HackerList } from './HackerList' +export * from './HackerList' diff --git a/packages/hackathon/src/scenes/UsersScene/index.ts b/packages/hackathon/src/scenes/UsersScene/index.ts index ca6079d4b..c28532f6c 100644 --- a/packages/hackathon/src/scenes/UsersScene/index.ts +++ b/packages/hackathon/src/scenes/UsersScene/index.ts @@ -23,4 +23,4 @@ SOFTWARE. */ -export { UsersScene } from './UsersScene' +export * from './UsersScene' diff --git a/packages/hackathon/src/scenes/index.ts b/packages/hackathon/src/scenes/index.ts index 522880b81..8543f3d43 100644 --- a/packages/hackathon/src/scenes/index.ts +++ b/packages/hackathon/src/scenes/index.ts @@ -23,12 +23,13 @@ SOFTWARE. */ -export { HomeScene } from './HomeScene' -export { ProjectsScene } from './ProjectsScene' -export { UsersScene } from './UsersScene' -export { JudgingScene } from './JudgingScene' -export { JudgingEditorScene } from './JudgingEditorScene' -export { AdminScene } from './AdminScene' -export { NotFoundScene } from './NotFoundScene' -export { ProjectEditorScene } from './ProjectEditorScene' -export { ResourceScene } from './ResourceScene' + +export * from './HomeScene' +export * from './ProjectsScene' +export * from './UsersScene' +export * from './JudgingScene' +export * from './JudgingEditorScene' +export * from './AdminScene' +export * from './NotFoundScene' +export * from './ProjectEditorScene' +export * from './ResourceScene'