From f415ac688ed4d31748b17333f69110b00ef5dd40 Mon Sep 17 00:00:00 2001 From: Amitosh Swain Mahapatra Date: Sun, 7 Feb 2021 17:59:13 +0530 Subject: [PATCH] Add One on One page --- frontend/src/components/App.tsx | 4 +- frontend/src/components/Snowflake.tsx | 9 +- frontend/src/components/header/Navbar.tsx | 4 +- .../components/one-on-ones/OneOnOneDetail.tsx | 89 +++++++++++++++++++ .../components/one-on-ones/OneOnOnesList.tsx | 54 +++++++++++ .../components/one-on-ones/OneOnOnesPage.tsx | 23 +++++ .../one-on-ones/ScheduleMeetingButton.tsx | 12 +++ frontend/src/lib/api.ts | 26 ++++++ frontend/src/lib/utils.ts | 6 +- 9 files changed, 220 insertions(+), 7 deletions(-) create mode 100644 frontend/src/components/one-on-ones/OneOnOneDetail.tsx create mode 100644 frontend/src/components/one-on-ones/OneOnOnesList.tsx create mode 100644 frontend/src/components/one-on-ones/OneOnOnesPage.tsx create mode 100644 frontend/src/components/one-on-ones/ScheduleMeetingButton.tsx diff --git a/frontend/src/components/App.tsx b/frontend/src/components/App.tsx index 763e9d9..d863b64 100644 --- a/frontend/src/components/App.tsx +++ b/frontend/src/components/App.tsx @@ -14,10 +14,10 @@ export default function App() { - + - + diff --git a/frontend/src/components/Snowflake.tsx b/frontend/src/components/Snowflake.tsx index b27e420..8ec686c 100644 --- a/frontend/src/components/Snowflake.tsx +++ b/frontend/src/components/Snowflake.tsx @@ -1,8 +1,9 @@ import React from "react"; import Navbar from "./header/Navbar"; -import {Route, Switch} from "react-router-dom"; +import {Redirect, Route, Switch} from "react-router-dom"; import FeedPage from "./feed/FeedPage"; import styles from './Snowflake.module.css'; +import OneOnOnesPage from "./one-on-ones/OneOnOnesPage"; export default function Snowflake() { return ( @@ -10,7 +11,11 @@ export default function Snowflake() {
- + + + + +
diff --git a/frontend/src/components/header/Navbar.tsx b/frontend/src/components/header/Navbar.tsx index 4e4f883..fa1b108 100644 --- a/frontend/src/components/header/Navbar.tsx +++ b/frontend/src/components/header/Navbar.tsx @@ -27,8 +27,8 @@ export default function Navbar() {
- - + + diff --git a/frontend/src/components/one-on-ones/OneOnOneDetail.tsx b/frontend/src/components/one-on-ones/OneOnOneDetail.tsx new file mode 100644 index 0000000..5e706ad --- /dev/null +++ b/frontend/src/components/one-on-ones/OneOnOneDetail.tsx @@ -0,0 +1,89 @@ +import {Link, useParams} from "react-router-dom"; +import React, {useCallback} from "react"; +import {oneOnOneById} from "../../lib/api"; +import {useAsync} from "../../hooks/use-async"; +import {useAuth} from "../../hooks/use-auth"; +import Loading from "../Loading"; +import {isCreatedByUser} from "../../lib/utils"; +import ScheduleMeetingButton from "./ScheduleMeetingButton"; + +type OneOnOneDetailRouterParams = { + id: string +} + +export default function OneOnOneDetail() { + const {id} = useParams(); + const loadOneOnOneById = useCallback(() => oneOnOneById(id), [id]); + const {value: oneOnOne, status} = useAsync(loadOneOnOneById); + const {user} = useAuth(); + + return ( +
+ {status === "pending" && } + {oneOnOne && ( +
+
+
+ {oneOnOne.createdBy.name} +
+
+ {oneOnOne.user.name} +
+
+
+
+
+

+ {isCreatedByUser(oneOnOne, user) ? + `Your 1:1 with ${oneOnOne.user.name}` : + `${oneOnOne.createdBy.name}}'s 1:1 with you`} +

+ +
+
+

Action items

+
    + {oneOnOne.actionItems.map(actionItem => ( +
  • + + + {`Created + + + {actionItem.createdBy.name} + + + {actionItem.content} + {/*TODO: add_mentions */} + +
  • + ))} +
+
+
+ + + + +
+
+
+
+
+
)} +
); +} diff --git a/frontend/src/components/one-on-ones/OneOnOnesList.tsx b/frontend/src/components/one-on-ones/OneOnOnesList.tsx new file mode 100644 index 0000000..611db93 --- /dev/null +++ b/frontend/src/components/one-on-ones/OneOnOnesList.tsx @@ -0,0 +1,54 @@ +import {useAsync} from "../../hooks/use-async"; +import {oneOnOnes} from "../../lib/api"; +import {useAuth} from "../../hooks/use-auth"; +import Loading from "../Loading"; +import {isCreatedByUser} from "../../lib/utils"; +import React from "react"; +import { Link } from "react-router-dom"; + +export default function OneOnOneList() { + + const {value: oneOnOneList, status} = useAsync(oneOnOnes); + const {user} = useAuth(); + + return ( +
+

+ People + +

+ {status === "pending" && } +
    + {oneOnOneList?.map(oneOnOne => ( +
  • + +
    +
    + Avatar of {{ o.created_by.name }} +
    +
    + Avatar of {{ o.user.name }} +
    +
    +
    +

    + {isCreatedByUser(oneOnOne, user) ? oneOnOne.user.name : oneOnOne.createdBy.name} +

    +

    + {isCreatedByUser(oneOnOne, user) ? oneOnOne.user.designation : oneOnOne.createdBy.designation} +

    +
    + +
  • + ))} +
+
); +} diff --git a/frontend/src/components/one-on-ones/OneOnOnesPage.tsx b/frontend/src/components/one-on-ones/OneOnOnesPage.tsx new file mode 100644 index 0000000..ec299be --- /dev/null +++ b/frontend/src/components/one-on-ones/OneOnOnesPage.tsx @@ -0,0 +1,23 @@ +import React from "react"; +import OneOnOneList from "./OneOnOnesList"; +import OneOnOneDetail from "./OneOnOneDetail"; +import {Route, Switch} from "react-router-dom"; + + +export default function OneOnOnesPage() { + return ( +
+
+
+ +
+
+ + + + + +
+
+
) +} diff --git a/frontend/src/components/one-on-ones/ScheduleMeetingButton.tsx b/frontend/src/components/one-on-ones/ScheduleMeetingButton.tsx new file mode 100644 index 0000000..4e3a81a --- /dev/null +++ b/frontend/src/components/one-on-ones/ScheduleMeetingButton.tsx @@ -0,0 +1,12 @@ +import React from "react"; + +export default function ScheduleMeetingButton({title}: { title: string }) { + return ( + + + + + Schedule + ) +} diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 033f0fa..765bc85 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -25,6 +25,24 @@ export type Appreciation = { viewerLike: Like } +export type OneOnOne = { + id: number, + user: User, + createdAt: string, + createdBy: User +} + +export type OneOnOneActionItem = { + id: number, + state: boolean + content: string + createdBy: User +} + +export type OneOnOneDetail = OneOnOne & { + actionItems: OneOnOneActionItem[] +} + async function get(url: string): Promise { const response = await axios.get(url, { headers: authorizationHeaders() @@ -48,3 +66,11 @@ export async function appreciationComments(id: number): Promise { export async function appreciationLikes(id: number): Promise { return get(`/api/appreciations/${id}/likes`); } + +export async function oneOnOnes(): Promise { + return get("/api/one_on_ones") +} + +export async function oneOnOneById(id: number | string): Promise { + return get(`/api/one_on_ones/${id}`) +} diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 6eb3ab4..2ed1001 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -1,7 +1,11 @@ -import {token} from "./auth"; +import {token, User} from "./auth"; export function authorizationHeaders() { return { 'Authorization': `Bearer ${token()}` } } + +export function isCreatedByUser(object: { createdBy?: User }, user?: User) { + return user?.username === object.createdBy?.username; +}