From b3cb1642e8316f9e806e5987d7329d361a8bd04c Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Mon, 12 Sep 2022 22:07:40 +0300 Subject: [PATCH 1/8] Implements GAME-81 --- package.json | 1 + .../environment.default.config.ts | 3 + .../environments/environment.dev.config.ts | 3 + .../environments/environment.prod.config.ts | 3 + src-ts/lib/global-config.model.ts | 3 + src-ts/lib/svgs/Icon-column-sort.svg | 3 + src-ts/lib/svgs/index.ts | 4 +- .../gamification-admin/GamificationAdmin.tsx | 11 +- .../gamification-admin.routes.tsx | 2 +- .../pages/badge-detail/BadgeDetailPage.tsx | 2 + .../BadgeListingPage.module.scss | 110 ++++++++++++++++-- .../pages/badge-listing/BadgeListingPage.tsx | 60 +++++++++- yarn.lock | 5 + 13 files changed, 189 insertions(+), 21 deletions(-) create mode 100644 src-ts/lib/svgs/Icon-column-sort.svg diff --git a/package.json b/package.json index bf9628928..588b91442 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "redux-thunk": "^2.4.1", "sass": "^1.49.8", "styled-components": "^5.3.5", + "swr": "^1.3.0", "tc-auth-lib": "topcoder-platform/tc-auth-lib#1.0.4", "typescript": "^4.6.3", "uuid": "^8.3.2" diff --git a/src-ts/config/environments/environment.default.config.ts b/src-ts/config/environments/environment.default.config.ts index 8df336dc1..0195d6daa 100644 --- a/src-ts/config/environments/environment.default.config.ts +++ b/src-ts/config/environments/environment.default.config.ts @@ -14,6 +14,9 @@ export const EnvironmentConfigDefault: EnvironmentConfigModel = { V5: 'https://api.topcoder-dev.com/v5', }, ENV: 'default', + GAMIFICATION: { + ORG_ID: '6052dd9b-ea80-494b-b258-edd1331e27a3', + }, LOGGING: { PUBLIC_TOKEN: 'puba0825671e469d16f940c5a30dc738f11', SERVICE: 'platform-ui', diff --git a/src-ts/config/environments/environment.dev.config.ts b/src-ts/config/environments/environment.dev.config.ts index 61c8ec1e7..be58c0381 100644 --- a/src-ts/config/environments/environment.dev.config.ts +++ b/src-ts/config/environments/environment.dev.config.ts @@ -9,6 +9,9 @@ export const EnvironmentConfigDev: EnvironmentConfigModel = { }, DISABLED_TOOLS: [], ENV: 'dev', + GAMIFICATION: { + ORG_ID: '6052dd9b-ea80-494b-b258-edd1331e27a3', + }, // TODO: Move stripe creds to .env file STRIPE: { ADMIN_TOKEN: diff --git a/src-ts/config/environments/environment.prod.config.ts b/src-ts/config/environments/environment.prod.config.ts index 4e4bd4e6b..a13f50dff 100644 --- a/src-ts/config/environments/environment.prod.config.ts +++ b/src-ts/config/environments/environment.prod.config.ts @@ -17,6 +17,9 @@ export const EnvironmentConfigProd: EnvironmentConfigModel = { }, DISABLED_TOOLS: [], ENV: 'prod', + GAMIFICATION: { + ORG_ID: 'e111f8df-6ac8-44d1-b4da-bb916f5e3425', + }, // TODO: Move stripe creds to .env file STRIPE: { ADMIN_TOKEN: diff --git a/src-ts/lib/global-config.model.ts b/src-ts/lib/global-config.model.ts index ddf9b8ce4..10fde8e9c 100644 --- a/src-ts/lib/global-config.model.ts +++ b/src-ts/lib/global-config.model.ts @@ -11,6 +11,9 @@ export interface GlobalConfig { } DISABLED_TOOLS?: Array ENV: string + GAMIFICATION: { + ORG_ID: string + }, LOGGING: { PUBLIC_TOKEN: string SERVICE: string diff --git a/src-ts/lib/svgs/Icon-column-sort.svg b/src-ts/lib/svgs/Icon-column-sort.svg new file mode 100644 index 000000000..ab0226b61 --- /dev/null +++ b/src-ts/lib/svgs/Icon-column-sort.svg @@ -0,0 +1,3 @@ + + + diff --git a/src-ts/lib/svgs/index.ts b/src-ts/lib/svgs/index.ts index 55c230790..2bd3eda58 100644 --- a/src-ts/lib/svgs/index.ts +++ b/src-ts/lib/svgs/index.ts @@ -7,6 +7,7 @@ import { ReactComponent as GithubIcon } from './github.svg' import { ReactComponent as GitlabIcon } from './gitlab.svg' import { ReactComponent as ArrowIcon } from './icon-arrow.svg' import { ReactComponent as BackArrowIcon } from './icon-back-arrow.svg' +import { ReactComponent as ColumnSortIcon } from './Icon-column-sort.svg' import { ReactComponent as LogoIcon } from './logo.svg' import { ReactComponent as SocialIconFacebook } from './social-fb-icon.svg' import { ReactComponent as SocialIconInstagram } from './social-insta-icon.svg' @@ -35,5 +36,6 @@ export { SocialShareLinkedIn, TooltipArrowIcon, GitlabIcon, - GithubIcon + GithubIcon, + ColumnSortIcon } diff --git a/src-ts/tools/gamification-admin/GamificationAdmin.tsx b/src-ts/tools/gamification-admin/GamificationAdmin.tsx index 860b2c3ae..ec6fd9be2 100644 --- a/src-ts/tools/gamification-admin/GamificationAdmin.tsx +++ b/src-ts/tools/gamification-admin/GamificationAdmin.tsx @@ -1,10 +1,12 @@ import { FC, useContext } from 'react' import { Outlet, Routes } from 'react-router-dom' +import { SWRConfig } from 'swr' import { routeContext, RouteContextData, } from '../../lib' +import { getAsync } from '../../lib/functions/xhr-functions/xhr.functions' export const toolTitle: string = 'Gamification Admin' @@ -13,12 +15,17 @@ const GamificationAdmin: FC<{}> = () => { const { getChildRoutes }: RouteContextData = useContext(routeContext) return ( - <> + getAsync(resource), + refreshInterval: 60000, // 1 min + }} + > {getChildRoutes(toolTitle)} - + ) } diff --git a/src-ts/tools/gamification-admin/gamification-admin.routes.tsx b/src-ts/tools/gamification-admin/gamification-admin.routes.tsx index 5b8a60acd..24ee0b8c1 100644 --- a/src-ts/tools/gamification-admin/gamification-admin.routes.tsx +++ b/src-ts/tools/gamification-admin/gamification-admin.routes.tsx @@ -22,7 +22,7 @@ export const gamificationAdminRoutes: Array = [ }, { element: , - route: '/badge-detail', + route: '/badge-detail/:id', }, ], element: , diff --git a/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx b/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx index 4923e6c95..a609b4ecb 100644 --- a/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx @@ -1,4 +1,5 @@ import { FC, useMemo } from 'react' +// import { useParams } from 'react-router-dom' import { Breadcrumb, BreadcrumbItemModel, ContentLayout } from '../../../../lib' import { baseUrl } from '../../gamification-admin.routes' @@ -7,6 +8,7 @@ import { toolTitle } from '../../GamificationAdmin' import styles from './BadgeDetailPage.module.scss' const BadgeDetailPage: FC = () => { + // const { id: badgeID } : { badgeID: string } = useParams() const breadcrumb: Array = useMemo(() => [ { name: toolTitle, url: baseUrl }, { name: 'badge detail', url: '#' }, diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss index 7da13b030..175072a97 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss +++ b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss @@ -1,17 +1,105 @@ -.contentLayout { - width: 100%; - padding-bottom: 0; +@import "../../../../lib/styles/includes"; - .contentLayout-outer { - width: 100%; +.container { + display: flex; + flex-direction: column; + padding-top: 32px; + + .badges-table-header { + display: flex; + justify-content: space-between; + padding-bottom: 17px; + color: #767676; + @include font-barlow; + @include font-weight-semibold; + font-size: 11px; + line-height: 11px; + + .col-sort { + display: flex; + margin-left: 94px; + + svg { + margin-left: 6px; + cursor: pointer; + } + } + + div:last-child { + margin-right: 100px; - .contentLayout-inner { - width: 100%; - overflow: visible; + @media (max-width: 768px) { + display: none; + } } } -} -.container { - display: flex; + .badges-table { + display: flex; + flex-direction: column; + + .badge-row { + display: flex; + justify-content: space-between; + padding: 16px 24px; + + @media (max-width: 768px) { + flex-direction: column; + } + + &:nth-child(odd) { + background-color: #F4F4F4; + border-radius: 8px; + } + + .badge { + display: flex; + align-items: center; + + .badge-image { + width: 48px; + height: 48px; + margin-right: 20px; + } + + .badge-image-disabled { + width: 48px; + height: 48px; + margin-right: 20px; + opacity: 0.5; + filter: grayscale(1); + } + + .badge-name { + font-size: 16px; + font-weight: 700; + line-height: 24px; + color: #2a2a2a; + } + } + + .actions { + display: flex; + align-items: center; + + @media (max-width: 768px) { + margin: 8px 0; + } + + .action-btn { + margin-right: 8px; + + &:last-child { + margin-right: 0; + } + } + } + } + } + + .loadbtn-wrap { + display: flex; + justify-content: center; + flex: 1; + } } diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx index 04fca91ee..4f30e3c2e 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx @@ -1,20 +1,68 @@ -import { FC } from 'react' +import { FC, useState } from 'react' +import { NavigateFunction, useNavigate } from 'react-router-dom' +// tslint:disable-next-line +import useSWRInfinite from 'swr/infinite' -import { ContentLayout } from '../../../../lib' +import { EnvironmentConfig } from '../../../../config' +import { Button, ButtonProps, ColumnSortIcon, ContentLayout, LoadingSpinner } from '../../../../lib' +import { baseUrl } from '../../gamification-admin.routes' import styles from './BadgeListingPage.module.scss' const BadgeListingPage: FC = () => { + const [order, setOrder]: any = useState({ by: 'badge_name', type: 'asc' }) + const navigate: NavigateFunction = useNavigate() + const getKey: any = (pageIndex: any, previousPageData: any) => { + if (previousPageData && !previousPageData.rows.length) { return undefined } // reached the end + return `${EnvironmentConfig.API.V5}/gamification/badges?organization_id=${EnvironmentConfig.GAMIFICATION.ORG_ID}&limit=12&offset=${pageIndex * 12}&order_by=${order.by}&order_type=${order.type}` + } + const { data: badges, size, setSize }: any = useSWRInfinite(getKey, { revalidateFirstPage: false }) + const loadedCnt: any = badges?.reduce((ps: any, a: any) => ps + a.rows.length, 0) + + const buttonConfig: ButtonProps = { + label: 'Create New Badge', + onClick: () => navigate(`${baseUrl}/create-badge`), + } + + if (!badges) { return } return (
- +
+
BADGE NAME { + setOrder({ + by: order.by, + type: order.type === 'asc' ? 'desc' : 'asc', + }) + }} />
+
ACTIONS
+
+
+ { + badges.map((page: any) => page.rows.map((badge: any) =>
+
+ {badge.badge_name} +

{badge.badge_name}

+
+
+
+
+ )) + } +
+ { + badges[0].count !== loadedCnt &&
+
+ }
) diff --git a/yarn.lock b/yarn.lock index 301fcda10..734710196 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14537,6 +14537,11 @@ svgo@^2.7.0: picocolors "^1.0.0" stable "^0.1.8" +swr@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/swr/-/swr-1.3.0.tgz#c6531866a35b4db37b38b72c45a63171faf9f4e8" + integrity sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw== + symbol-tree@^3.2.2, symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" From fe1153eeab0ab5a2b8461f3851b90f6a81a3f331 Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Wed, 14 Sep 2022 10:19:35 +0300 Subject: [PATCH 2/8] code review updates --- .../environment.default.config.ts | 3 --- .../environments/environment.dev.config.ts | 3 --- .../environments/environment.prod.config.ts | 3 --- .../gamification-admin/GamificationAdmin.tsx | 4 +-- .../config/gamification-config.model.ts | 3 +++ .../config/gamification.config.ts | 27 +++++++++++++++++++ .../config/gamification.default.config.ts | 5 ++++ .../config/gamification.dev.config.ts | 5 ++++ .../config/gamification.prod.config.ts | 5 ++++ .../tools/gamification-admin/config/index.ts | 1 + .../lib/hooks/getDataSource.ts | 5 ++++ .../pages/badge-detail/BadgeDetailPage.tsx | 1 - .../BadgeListingPage.module.scss | 2 +- .../pages/badge-listing/BadgeListingPage.tsx | 6 +++-- 14 files changed, 58 insertions(+), 15 deletions(-) create mode 100644 src-ts/tools/gamification-admin/config/gamification-config.model.ts create mode 100644 src-ts/tools/gamification-admin/config/gamification.config.ts create mode 100644 src-ts/tools/gamification-admin/config/gamification.default.config.ts create mode 100644 src-ts/tools/gamification-admin/config/gamification.dev.config.ts create mode 100644 src-ts/tools/gamification-admin/config/gamification.prod.config.ts create mode 100644 src-ts/tools/gamification-admin/config/index.ts create mode 100644 src-ts/tools/gamification-admin/lib/hooks/getDataSource.ts diff --git a/src-ts/config/environments/environment.default.config.ts b/src-ts/config/environments/environment.default.config.ts index 0195d6daa..8df336dc1 100644 --- a/src-ts/config/environments/environment.default.config.ts +++ b/src-ts/config/environments/environment.default.config.ts @@ -14,9 +14,6 @@ export const EnvironmentConfigDefault: EnvironmentConfigModel = { V5: 'https://api.topcoder-dev.com/v5', }, ENV: 'default', - GAMIFICATION: { - ORG_ID: '6052dd9b-ea80-494b-b258-edd1331e27a3', - }, LOGGING: { PUBLIC_TOKEN: 'puba0825671e469d16f940c5a30dc738f11', SERVICE: 'platform-ui', diff --git a/src-ts/config/environments/environment.dev.config.ts b/src-ts/config/environments/environment.dev.config.ts index be58c0381..61c8ec1e7 100644 --- a/src-ts/config/environments/environment.dev.config.ts +++ b/src-ts/config/environments/environment.dev.config.ts @@ -9,9 +9,6 @@ export const EnvironmentConfigDev: EnvironmentConfigModel = { }, DISABLED_TOOLS: [], ENV: 'dev', - GAMIFICATION: { - ORG_ID: '6052dd9b-ea80-494b-b258-edd1331e27a3', - }, // TODO: Move stripe creds to .env file STRIPE: { ADMIN_TOKEN: diff --git a/src-ts/config/environments/environment.prod.config.ts b/src-ts/config/environments/environment.prod.config.ts index a13f50dff..4e4bd4e6b 100644 --- a/src-ts/config/environments/environment.prod.config.ts +++ b/src-ts/config/environments/environment.prod.config.ts @@ -17,9 +17,6 @@ export const EnvironmentConfigProd: EnvironmentConfigModel = { }, DISABLED_TOOLS: [], ENV: 'prod', - GAMIFICATION: { - ORG_ID: 'e111f8df-6ac8-44d1-b4da-bb916f5e3425', - }, // TODO: Move stripe creds to .env file STRIPE: { ADMIN_TOKEN: diff --git a/src-ts/tools/gamification-admin/GamificationAdmin.tsx b/src-ts/tools/gamification-admin/GamificationAdmin.tsx index ec6fd9be2..3d85c3598 100644 --- a/src-ts/tools/gamification-admin/GamificationAdmin.tsx +++ b/src-ts/tools/gamification-admin/GamificationAdmin.tsx @@ -5,8 +5,8 @@ import { SWRConfig } from 'swr' import { routeContext, RouteContextData, + xhrGetAsync, } from '../../lib' -import { getAsync } from '../../lib/functions/xhr-functions/xhr.functions' export const toolTitle: string = 'Gamification Admin' @@ -17,7 +17,7 @@ const GamificationAdmin: FC<{}> = () => { return ( getAsync(resource), + fetcher: (resource) => xhrGetAsync(resource), refreshInterval: 60000, // 1 min }} > diff --git a/src-ts/tools/gamification-admin/config/gamification-config.model.ts b/src-ts/tools/gamification-admin/config/gamification-config.model.ts new file mode 100644 index 000000000..f090f1389 --- /dev/null +++ b/src-ts/tools/gamification-admin/config/gamification-config.model.ts @@ -0,0 +1,3 @@ +export interface GamificationConfigModel { + ORG_ID: string +} diff --git a/src-ts/tools/gamification-admin/config/gamification.config.ts b/src-ts/tools/gamification-admin/config/gamification.config.ts new file mode 100644 index 000000000..e204a4040 --- /dev/null +++ b/src-ts/tools/gamification-admin/config/gamification.config.ts @@ -0,0 +1,27 @@ +import { EnvironmentConfig } from '../../../config' + +import { GamificationConfigModel } from './gamification-config.model' +import { GamificationConfigDefault } from './gamification.default.config' +import { GamificationConfigDev } from './gamification.dev.config' +import { GamificationConfigProd } from './gamification.prod.config' + +function getConfig(): GamificationConfigModel { + + switch (EnvironmentConfig.ENV) { + + case 'dev': + return GamificationConfigDev + + case 'prod': + return GamificationConfigProd + + default: + return GamificationConfigDefault + } +} + +const GamificationConfig: GamificationConfigModel = { + ...getConfig(), +} + +export default GamificationConfig diff --git a/src-ts/tools/gamification-admin/config/gamification.default.config.ts b/src-ts/tools/gamification-admin/config/gamification.default.config.ts new file mode 100644 index 000000000..aa7ad4626 --- /dev/null +++ b/src-ts/tools/gamification-admin/config/gamification.default.config.ts @@ -0,0 +1,5 @@ +import { GamificationConfigModel } from './gamification-config.model' + +export const GamificationConfigDefault: GamificationConfigModel = { + ORG_ID: '6052dd9b-ea80-494b-b258-edd1331e27a3', +} diff --git a/src-ts/tools/gamification-admin/config/gamification.dev.config.ts b/src-ts/tools/gamification-admin/config/gamification.dev.config.ts new file mode 100644 index 000000000..63bd27ddf --- /dev/null +++ b/src-ts/tools/gamification-admin/config/gamification.dev.config.ts @@ -0,0 +1,5 @@ +import { GamificationConfigModel } from './gamification-config.model' + +export const GamificationConfigDev: GamificationConfigModel = { + ORG_ID: '6052dd9b-ea80-494b-b258-edd1331e27a3', +} diff --git a/src-ts/tools/gamification-admin/config/gamification.prod.config.ts b/src-ts/tools/gamification-admin/config/gamification.prod.config.ts new file mode 100644 index 000000000..922edc652 --- /dev/null +++ b/src-ts/tools/gamification-admin/config/gamification.prod.config.ts @@ -0,0 +1,5 @@ +import { GamificationConfigModel } from './gamification-config.model' + +export const GamificationConfigProd: GamificationConfigModel = { + ORG_ID: 'e111f8df-6ac8-44d1-b4da-bb916f5e3425', +} diff --git a/src-ts/tools/gamification-admin/config/index.ts b/src-ts/tools/gamification-admin/config/index.ts new file mode 100644 index 000000000..60ed70fc0 --- /dev/null +++ b/src-ts/tools/gamification-admin/config/index.ts @@ -0,0 +1 @@ +export { default as GamificationConfig } from './gamification.config' diff --git a/src-ts/tools/gamification-admin/lib/hooks/getDataSource.ts b/src-ts/tools/gamification-admin/lib/hooks/getDataSource.ts new file mode 100644 index 000000000..d81ffdcab --- /dev/null +++ b/src-ts/tools/gamification-admin/lib/hooks/getDataSource.ts @@ -0,0 +1,5 @@ +import { EnvironmentConfig } from '../../../../config' + +export default function getDataSource(): string { + return `${EnvironmentConfig.API.V5}/gamification` +} diff --git a/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx b/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx index a609b4ecb..c58a04227 100644 --- a/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx @@ -1,5 +1,4 @@ import { FC, useMemo } from 'react' -// import { useParams } from 'react-router-dom' import { Breadcrumb, BreadcrumbItemModel, ContentLayout } from '../../../../lib' import { baseUrl } from '../../gamification-admin.routes' diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss index 175072a97..2be19a603 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss +++ b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss @@ -28,7 +28,7 @@ div:last-child { margin-right: 100px; - @media (max-width: 768px) { + @include ltemd { display: none; } } diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx index 4f30e3c2e..053b17b28 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx @@ -3,18 +3,20 @@ import { NavigateFunction, useNavigate } from 'react-router-dom' // tslint:disable-next-line import useSWRInfinite from 'swr/infinite' -import { EnvironmentConfig } from '../../../../config' import { Button, ButtonProps, ColumnSortIcon, ContentLayout, LoadingSpinner } from '../../../../lib' +import { GamificationConfig } from '../../config' import { baseUrl } from '../../gamification-admin.routes' +import getDataSource from '../../lib/hooks/getDataSource' import styles from './BadgeListingPage.module.scss' const BadgeListingPage: FC = () => { const [order, setOrder]: any = useState({ by: 'badge_name', type: 'asc' }) const navigate: NavigateFunction = useNavigate() + const dataSource: string = getDataSource() const getKey: any = (pageIndex: any, previousPageData: any) => { if (previousPageData && !previousPageData.rows.length) { return undefined } // reached the end - return `${EnvironmentConfig.API.V5}/gamification/badges?organization_id=${EnvironmentConfig.GAMIFICATION.ORG_ID}&limit=12&offset=${pageIndex * 12}&order_by=${order.by}&order_type=${order.type}` + return `${dataSource}/badges?organization_id=${GamificationConfig.ORG_ID}&limit=12&offset=${pageIndex * 12}&order_by=${order.by}&order_type=${order.type}` } const { data: badges, size, setSize }: any = useSWRInfinite(getKey, { revalidateFirstPage: false }) const loadedCnt: any = badges?.reduce((ps: any, a: any) => ps + a.rows.length, 0) From 126806e3e3f414d421399a121b2d04a18311fe3a Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Wed, 14 Sep 2022 12:00:26 +0300 Subject: [PATCH 3/8] switch to heroicon for sort column trigger --- src-ts/lib/svgs/Icon-column-sort.svg | 3 -- src-ts/lib/svgs/index.ts | 4 +-- .../BadgeListingPage.module.scss | 7 +++-- .../pages/badge-listing/BadgeListingPage.tsx | 28 +++++++++++++------ 4 files changed, 24 insertions(+), 18 deletions(-) delete mode 100644 src-ts/lib/svgs/Icon-column-sort.svg diff --git a/src-ts/lib/svgs/Icon-column-sort.svg b/src-ts/lib/svgs/Icon-column-sort.svg deleted file mode 100644 index ab0226b61..000000000 --- a/src-ts/lib/svgs/Icon-column-sort.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src-ts/lib/svgs/index.ts b/src-ts/lib/svgs/index.ts index 2bd3eda58..55c230790 100644 --- a/src-ts/lib/svgs/index.ts +++ b/src-ts/lib/svgs/index.ts @@ -7,7 +7,6 @@ import { ReactComponent as GithubIcon } from './github.svg' import { ReactComponent as GitlabIcon } from './gitlab.svg' import { ReactComponent as ArrowIcon } from './icon-arrow.svg' import { ReactComponent as BackArrowIcon } from './icon-back-arrow.svg' -import { ReactComponent as ColumnSortIcon } from './Icon-column-sort.svg' import { ReactComponent as LogoIcon } from './logo.svg' import { ReactComponent as SocialIconFacebook } from './social-fb-icon.svg' import { ReactComponent as SocialIconInstagram } from './social-insta-icon.svg' @@ -36,6 +35,5 @@ export { SocialShareLinkedIn, TooltipArrowIcon, GitlabIcon, - GithubIcon, - ColumnSortIcon + GithubIcon } diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss index 2be19a603..5d566a4fc 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss +++ b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss @@ -1,4 +1,5 @@ @import "../../../../lib/styles/includes"; +@import "../../../../lib/styles/variables"; .container { display: flex; @@ -9,7 +10,7 @@ display: flex; justify-content: space-between; padding-bottom: 17px; - color: #767676; + color: $black-60; @include font-barlow; @include font-weight-semibold; font-size: 11px; @@ -18,10 +19,10 @@ .col-sort { display: flex; margin-left: 94px; + align-items: center; svg { - margin-left: 6px; - cursor: pointer; + color: $black-100; } } diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx index 053b17b28..ab8013099 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx @@ -1,9 +1,9 @@ import { FC, useState } from 'react' import { NavigateFunction, useNavigate } from 'react-router-dom' // tslint:disable-next-line -import useSWRInfinite from 'swr/infinite' +import useSWRInfinite from 'swr/infinite' -import { Button, ButtonProps, ColumnSortIcon, ContentLayout, LoadingSpinner } from '../../../../lib' +import { Button, ButtonProps, ContentLayout, IconOutline, LoadingSpinner } from '../../../../lib' import { GamificationConfig } from '../../config' import { baseUrl } from '../../gamification-admin.routes' import getDataSource from '../../lib/hooks/getDataSource' @@ -20,6 +20,12 @@ const BadgeListingPage: FC = () => { } const { data: badges, size, setSize }: any = useSWRInfinite(getKey, { revalidateFirstPage: false }) const loadedCnt: any = badges?.reduce((ps: any, a: any) => ps + a.rows.length, 0) + const onOrderClick: any = () => { + setOrder({ + by: order.by, + type: order.type === 'asc' ? 'desc' : 'asc', + }) + } const buttonConfig: ButtonProps = { label: 'Create New Badge', @@ -35,12 +41,16 @@ const BadgeListingPage: FC = () => { >
-
BADGE NAME { - setOrder({ - by: order.by, - type: order.type === 'asc' ? 'desc' : 'asc', - }) - }} />
+
+ BADGE NAME + { + order.type === 'asc' ? ( +
ACTIONS
@@ -51,7 +61,7 @@ const BadgeListingPage: FC = () => {

{badge.badge_name}

-
From c3ae18ad5b9b5b148e28ea51b699729016a9fc5d Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Wed, 14 Sep 2022 12:10:20 +0300 Subject: [PATCH 4/8] use _spacing whenever possible --- .../BadgeListingPage.module.scss | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss index 5d566a4fc..36db3452d 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss +++ b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.module.scss @@ -4,12 +4,12 @@ .container { display: flex; flex-direction: column; - padding-top: 32px; + padding-top: $space-xxxxl; .badges-table-header { display: flex; justify-content: space-between; - padding-bottom: 17px; + padding-bottom: $space-lg; color: $black-60; @include font-barlow; @include font-weight-semibold; @@ -42,14 +42,14 @@ .badge-row { display: flex; justify-content: space-between; - padding: 16px 24px; + padding: $space-lg $space-xxl; - @media (max-width: 768px) { + @include ltemd { flex-direction: column; } &:nth-child(odd) { - background-color: #F4F4F4; + background-color: $black-5; border-radius: 8px; } @@ -60,13 +60,13 @@ .badge-image { width: 48px; height: 48px; - margin-right: 20px; + margin-right: $space-xl; } .badge-image-disabled { width: 48px; height: 48px; - margin-right: 20px; + margin-right: $space-xl; opacity: 0.5; filter: grayscale(1); } @@ -75,7 +75,7 @@ font-size: 16px; font-weight: 700; line-height: 24px; - color: #2a2a2a; + color: $black-100; } } @@ -83,12 +83,12 @@ display: flex; align-items: center; - @media (max-width: 768px) { - margin: 8px 0; + @include ltemd { + margin: $space-sm 0; } .action-btn { - margin-right: 8px; + margin-right: $space-sm; &:last-child { margin-right: 0; From 40ef0defd5bcc62fdd997a38d569fc49d6a691c3 Mon Sep 17 00:00:00 2001 From: Kiril Kartunov Date: Mon, 19 Sep 2022 14:00:17 +0300 Subject: [PATCH 5/8] GAME-107 and GAME-99 --- src-ts/lib/table/Table.module.scss | 9 +++ src-ts/lib/table/Table.tsx | 22 +++++- src-ts/lib/table/table-column.model.ts | 1 + .../lib/models/badge.model.ts | 9 +++ .../pages/badge-detail/BadgeDetailPage.tsx | 1 + .../pages/badge-listing/BadgeListingPage.tsx | 76 +++++++++---------- .../BadgeActionRenderer.module.scss | 27 +++++++ .../BadgeActionRenderer.tsx | 19 +++++ .../badge-action-renderer/index.ts | 1 + .../badge-listing-table.config.tsx | 22 ++++++ .../BadgeListingNameRenderer.module.scss | 28 +++++++ .../BadgeListingNameRenderer.tsx | 14 ++++ .../badge-name-renderer/index.ts | 1 + 13 files changed, 187 insertions(+), 43 deletions(-) create mode 100644 src-ts/tools/gamification-admin/lib/models/badge.model.ts create mode 100644 src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.module.scss create mode 100644 src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.tsx create mode 100644 src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/index.ts create mode 100644 src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-listing-table.config.tsx create mode 100644 src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.module.scss create mode 100644 src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.tsx create mode 100644 src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/index.ts diff --git a/src-ts/lib/table/Table.module.scss b/src-ts/lib/table/Table.module.scss index eeb951071..5582e4c7c 100644 --- a/src-ts/lib/table/Table.module.scss +++ b/src-ts/lib/table/Table.module.scss @@ -61,6 +61,10 @@ margin-right: -29px; } } + + &.centerHeader { + justify-content: center; + } } .tooltip { @@ -90,3 +94,8 @@ .tootlipBody { min-width: 200px; } + +.loadBtnWrap { + display: flex; + justify-content: center; +} \ No newline at end of file diff --git a/src-ts/lib/table/Table.tsx b/src-ts/lib/table/Table.tsx index 25c439700..7858bb476 100644 --- a/src-ts/lib/table/Table.tsx +++ b/src-ts/lib/table/Table.tsx @@ -1,6 +1,7 @@ import classNames from 'classnames' import { Dispatch, MouseEvent, SetStateAction, useEffect, useState } from 'react' +import { Button, ButtonSize, ButtonStyle } from '../button' import { Sort } from '../pagination' import '../styles/_includes.scss' import { IconOutline } from '../svgs' @@ -15,7 +16,13 @@ import styles from './Table.module.scss' interface TableProps { readonly columns: ReadonlyArray> readonly data: ReadonlyArray + readonly loadMoreBtnLabel?: string + readonly loadMoreBtnSize?: ButtonSize + readonly loadMoreBtnStyle?: ButtonStyle + readonly moreToLoad?: boolean + readonly onLoadMoreClick?: (data: T) => void readonly onRowClick?: (data: T) => void + readonly onToggleSort?: (sort: Sort | undefined) => void } interface DefaultSortDirectionMap { @@ -75,6 +82,11 @@ const Table: (props: TableProps) = fieldName, } setSort(newSort) + + // call the callback to notify parent for sort update + if (props.onToggleSort) { + props.onToggleSort(newSort) + } } const headerRow: Array = props.columns @@ -83,12 +95,13 @@ const Table: (props: TableProps) = const isCurrentlySorted: boolean = isSortable && col.propertyName === sort?.fieldName const colorClass: string = isCurrentlySorted ? 'black-100' : 'black-60' const sortableClass: string | undefined = isSortable ? styles.sortable : undefined + const centerClass: string | undefined = col.centerHeader ? styles.centerHeader : undefined return ( -
+
{col.label} {!!col.tooltip && (
@@ -136,7 +149,7 @@ const Table: (props: TableProps) = // return the entire row return ( @@ -158,6 +171,11 @@ const Table: (props: TableProps) = {rowCells} + { + props.moreToLoad &&
+
+ }
) } diff --git a/src-ts/lib/table/table-column.model.ts b/src-ts/lib/table/table-column.model.ts index 4323da523..6d7ddb0c9 100644 --- a/src-ts/lib/table/table-column.model.ts +++ b/src-ts/lib/table/table-column.model.ts @@ -1,6 +1,7 @@ import { TableCellType } from './table-cell.type' export interface TableColumn { + readonly centerHeader?: boolean readonly defaultSortDirection?: 'asc' | 'desc' readonly isDefaultSort?: boolean readonly label?: string diff --git a/src-ts/tools/gamification-admin/lib/models/badge.model.ts b/src-ts/tools/gamification-admin/lib/models/badge.model.ts new file mode 100644 index 000000000..c88efeb78 --- /dev/null +++ b/src-ts/tools/gamification-admin/lib/models/badge.model.ts @@ -0,0 +1,9 @@ +export interface Badge { + active: boolean + badge_description: string + badge_image_url: string + badge_name: string + badge_status: string + id: string + organization_id: string +} diff --git a/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx b/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx index c58a04227..1e84dc1ed 100644 --- a/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx @@ -7,6 +7,7 @@ import { toolTitle } from '../../GamificationAdmin' import styles from './BadgeDetailPage.module.scss' const BadgeDetailPage: FC = () => { + // TDOD: use whit GAME-78 // const { id: badgeID } : { badgeID: string } = useParams() const breadcrumb: Array = useMemo(() => [ { name: toolTitle, url: baseUrl }, diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx index ab8013099..08dc7c2be 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx @@ -1,32 +1,51 @@ -import { FC, useState } from 'react' +import { flatten, map } from 'lodash' +import { Dispatch, FC, SetStateAction, useState } from 'react' import { NavigateFunction, useNavigate } from 'react-router-dom' // tslint:disable-next-line import useSWRInfinite from 'swr/infinite' -import { Button, ButtonProps, ContentLayout, IconOutline, LoadingSpinner } from '../../../../lib' +import { ButtonProps, ContentLayout, LoadingSpinner, Sort, Table, TableColumn } from '../../../../lib' import { GamificationConfig } from '../../config' import { baseUrl } from '../../gamification-admin.routes' import getDataSource from '../../lib/hooks/getDataSource' +import { Badge } from '../../lib/models/badge.model' +import { badgeListingColumns } from './badge-listing-table/badge-listing-table.config' import styles from './BadgeListingPage.module.scss' const BadgeListingPage: FC = () => { const [order, setOrder]: any = useState({ by: 'badge_name', type: 'asc' }) const navigate: NavigateFunction = useNavigate() const dataSource: string = getDataSource() + + // server-side pagination hook const getKey: any = (pageIndex: any, previousPageData: any) => { if (previousPageData && !previousPageData.rows.length) { return undefined } // reached the end return `${dataSource}/badges?organization_id=${GamificationConfig.ORG_ID}&limit=12&offset=${pageIndex * 12}&order_by=${order.by}&order_type=${order.type}` } const { data: badges, size, setSize }: any = useSWRInfinite(getKey, { revalidateFirstPage: false }) - const loadedCnt: any = badges?.reduce((ps: any, a: any) => ps + a.rows.length, 0) - const onOrderClick: any = () => { + + const tableData: Array = flatten(map(badges, page => page.rows)) // flatten version of badges paginated data + const loadedCnt: any = badges?.reduce((ps: any, a: any) => ps + a.rows.length, 0) // how much data is loaded so far + + // listing table config + const [columns]: [ + ReadonlyArray>, + Dispatch>>>, + ] + = useState>>([...badgeListingColumns]) + + // on sort toggle callback + const onOrderClick: any = (sort: Sort) => { setOrder({ - by: order.by, - type: order.type === 'asc' ? 'desc' : 'asc', + by: sort.fieldName, + type: sort.direction, }) } + // on load more callback + const onLoadMoreClick: any = () => setSize(size + 1) + // header button config const buttonConfig: ButtonProps = { label: 'Create New Badge', onClick: () => navigate(`${baseUrl}/create-badge`), @@ -40,41 +59,16 @@ const BadgeListingPage: FC = () => { buttonConfig={buttonConfig} >
-
-
- BADGE NAME - { - order.type === 'asc' ? ( -
-
ACTIONS
-
-
- { - badges.map((page: any) => page.rows.map((badge: any) =>
-
- {badge.badge_name} -

{badge.badge_name}

-
-
-
-
- )) - } -
- { - badges[0].count !== loadedCnt &&
-
- } + ) diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.module.scss b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.module.scss new file mode 100644 index 000000000..0ce6473f5 --- /dev/null +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.module.scss @@ -0,0 +1,27 @@ +@import "../../../../../../lib/styles/includes"; +@import "../../../../../../lib/styles/variables"; + +.badge-actions { + display: flex; + align-items: center; + justify-content: center; + padding-top: $space-lg; + + @include ltemd { + flex-direction: column; + align-items: flex-end; + } + + a { + margin-right: $space-sm; + + @include ltemd { + margin-right: 0; + margin-bottom: $space-sm; + } + + &:last-child { + margin-right: 0; + } + } +} \ No newline at end of file diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.tsx new file mode 100644 index 000000000..33972e587 --- /dev/null +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.tsx @@ -0,0 +1,19 @@ +import { Button, useCheckIsMobile } from '../../../../../../lib' +import { baseUrl } from '../../../../gamification-admin.routes' +import { Badge } from '../../../../lib/models/badge.model' + +import styles from './BadgeActionRenderer.module.scss' + +function BadgeActionRenderer(badge: Badge): JSX.Element { + const isMobile: boolean = useCheckIsMobile() + + return ( +
+
+ ) +} + +export default BadgeActionRenderer diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/index.ts b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/index.ts new file mode 100644 index 000000000..8324241f1 --- /dev/null +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/index.ts @@ -0,0 +1 @@ +export { default as BadgeActionRenderer } from './BadgeActionRenderer' diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-listing-table.config.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-listing-table.config.tsx new file mode 100644 index 000000000..ab9667ebf --- /dev/null +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-listing-table.config.tsx @@ -0,0 +1,22 @@ +import { TableColumn } from '../../../../../lib' +import { Badge } from '../../../lib/models/badge.model' + +import { BadgeActionRenderer } from './badge-action-renderer' +import { BadgeListingNameRenderer } from './badge-name-renderer' + +export const badgeListingColumns: ReadonlyArray> = [ + { + defaultSortDirection: 'asc', + isDefaultSort: true, + label: 'Badge Name', + propertyName: 'badge_name', + renderer: BadgeListingNameRenderer, + type: 'element', + }, + { + centerHeader: true, + label: 'Actions', + renderer: BadgeActionRenderer, + type: 'action', + }, +] diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.module.scss b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.module.scss new file mode 100644 index 000000000..0bbb9a231 --- /dev/null +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.module.scss @@ -0,0 +1,28 @@ +@import "../../../../../../lib/styles/includes"; +@import "../../../../../../lib/styles/variables"; + +.badge { + display: flex; + align-items: center; + + .badge-image { + width: 48px; + height: 48px; + margin-right: $space-xl; + } + + .badge-image-disabled { + width: 48px; + height: 48px; + margin-right: $space-xl; + opacity: 0.5; + filter: grayscale(1); + } + + .badge-name { + font-size: 16px; + font-weight: 700; + line-height: 24px; + color: $black-100; + } +} \ No newline at end of file diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.tsx new file mode 100644 index 000000000..333aed2e7 --- /dev/null +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.tsx @@ -0,0 +1,14 @@ +import { Badge } from '../../../../lib/models/badge.model' + +import styles from './BadgeListingNameRenderer.module.scss' + +function BadgeListingNameRenderer(badge: Badge): JSX.Element { + return ( +
+ {badge.badge_name} +

{badge.badge_name}

+
+ ) +} + +export default BadgeListingNameRenderer diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/index.ts b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/index.ts new file mode 100644 index 000000000..dac5de575 --- /dev/null +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/index.ts @@ -0,0 +1 @@ +export { default as BadgeListingNameRenderer } from './BadgeListingNameRenderer' From 9f833123e2f01640c83f5a208e72220b0f6a5de4 Mon Sep 17 00:00:00 2001 From: Brooke Date: Mon, 19 Sep 2022 15:53:46 -0700 Subject: [PATCH 6/8] GAME-107 #comment This commit refactors the SWR to be a generic hook that lives in the lib and can be re-used elsewhere. It makes the styling of the Load More button static. It moves everything to do w/routing to the .routes page and removes duplicate paths. It creates a breadccrumb provider for the Gamification tool so we're not duplicating the base item. It moves the retrieval of the badge info into a provider so that it's not directly in the presentation layer. #time 4h --- src-ts/lib/pagination/index.ts | 3 + .../lib/pagination/infinite-page-dao.model.ts | 4 + .../pagination/infinite-page-handler.model.ts | 5 + .../lib/pagination/use-infinite-page.hook.ts | 25 ++++ src-ts/lib/table/Table.tsx | 37 +++--- src-ts/lib/table/index.ts | 1 + src-ts/lib/table/table-column.model.ts | 1 - .../table/table-functions/table.functions.ts | 18 +-- .../gamification-config.model.ts | 1 + .../gamification.config.ts | 0 .../gamification.default.config.ts | 1 + .../gamification.dev.config.ts | 3 +- .../gamification.prod.config.ts | 2 + .../{config => game-config}/index.ts | 0 .../game-badge.model.ts} | 3 +- .../gamification-admin/game-lib/index.ts | 3 + .../game-lib/use-get-game-badges-page.hook.ts | 30 +++++ .../useGamificationBreadcrumb.provider.tsx | 16 +++ .../gamification-admin.routes.tsx | 22 +++- .../lib/hooks/getDataSource.ts | 5 - .../pages/badge-detail/BadgeDetailPage.tsx | 44 +++---- .../pages/badge-listing/BadgeListingPage.tsx | 109 ++++++++---------- .../BadgeActionRenderer.tsx | 54 +++++++-- .../badge-listing-table.config.tsx | 6 +- .../BadgeListingNameRenderer.tsx | 10 +- .../badge-listing-table/index.ts | 1 + .../pages/create-badge/CreateBadgePage.tsx | 40 ++++--- 27 files changed, 287 insertions(+), 157 deletions(-) create mode 100644 src-ts/lib/pagination/infinite-page-dao.model.ts create mode 100644 src-ts/lib/pagination/infinite-page-handler.model.ts create mode 100644 src-ts/lib/pagination/use-infinite-page.hook.ts rename src-ts/tools/gamification-admin/{config => game-config}/gamification-config.model.ts (75%) rename src-ts/tools/gamification-admin/{config => game-config}/gamification.config.ts (100%) rename src-ts/tools/gamification-admin/{config => game-config}/gamification.default.config.ts (91%) rename src-ts/tools/gamification-admin/{config => game-config}/gamification.dev.config.ts (56%) rename src-ts/tools/gamification-admin/{config => game-config}/gamification.prod.config.ts (63%) rename src-ts/tools/gamification-admin/{config => game-config}/index.ts (100%) rename src-ts/tools/gamification-admin/{lib/models/badge.model.ts => game-lib/game-badge.model.ts} (60%) create mode 100644 src-ts/tools/gamification-admin/game-lib/index.ts create mode 100644 src-ts/tools/gamification-admin/game-lib/use-get-game-badges-page.hook.ts create mode 100644 src-ts/tools/gamification-admin/game-lib/useGamificationBreadcrumb.provider.tsx delete mode 100644 src-ts/tools/gamification-admin/lib/hooks/getDataSource.ts create mode 100644 src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/index.ts diff --git a/src-ts/lib/pagination/index.ts b/src-ts/lib/pagination/index.ts index 3b90b0623..b8e69f71a 100644 --- a/src-ts/lib/pagination/index.ts +++ b/src-ts/lib/pagination/index.ts @@ -1,2 +1,5 @@ +export * from './infinite-page-dao.model' +export * from './infinite-page-handler.model' export * from './page.model' export * from './sort.model' +export * from './use-infinite-page.hook' diff --git a/src-ts/lib/pagination/infinite-page-dao.model.ts b/src-ts/lib/pagination/infinite-page-dao.model.ts new file mode 100644 index 000000000..2b2520095 --- /dev/null +++ b/src-ts/lib/pagination/infinite-page-dao.model.ts @@ -0,0 +1,4 @@ +export interface InfinitePageDao { + count: number + rows: ReadonlyArray +} diff --git a/src-ts/lib/pagination/infinite-page-handler.model.ts b/src-ts/lib/pagination/infinite-page-handler.model.ts new file mode 100644 index 000000000..cab09cc1a --- /dev/null +++ b/src-ts/lib/pagination/infinite-page-handler.model.ts @@ -0,0 +1,5 @@ +export interface InfinitePageHandler { + data?: ReadonlyArray + getAndSetNext: () => void + hasMore: boolean +} diff --git a/src-ts/lib/pagination/use-infinite-page.hook.ts b/src-ts/lib/pagination/use-infinite-page.hook.ts new file mode 100644 index 000000000..6f1367ea2 --- /dev/null +++ b/src-ts/lib/pagination/use-infinite-page.hook.ts @@ -0,0 +1,25 @@ +import { flatten, map } from 'lodash' +// tslint:disable-next-line: no-submodule-imports +import useSWRInfinite, { SWRInfiniteResponse } from 'swr/infinite' + +import { InfinitePageDao } from './infinite-page-dao.model' +import { InfinitePageHandler } from './infinite-page-handler.model' + +export function useGetInfinitePage(getKey: (index: number, previousPageData: InfinitePageDao) => string | undefined): + InfinitePageHandler { + + const { data, setSize, size }: SWRInfiniteResponse> = useSWRInfinite(getKey, { revalidateFirstPage: false }) + + // flatten version of badges paginated data + const outputData: ReadonlyArray = flatten(map(data, dao => dao.rows)) + + function getAndSetNext(): void { + setSize(size + 1) + } + + return { + data: outputData, + getAndSetNext, + hasMore: outputData.length < (data?.[0]?.count || 0), + } +} diff --git a/src-ts/lib/table/Table.tsx b/src-ts/lib/table/Table.tsx index 7858bb476..ad3443d25 100644 --- a/src-ts/lib/table/Table.tsx +++ b/src-ts/lib/table/Table.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames' import { Dispatch, MouseEvent, SetStateAction, useEffect, useState } from 'react' -import { Button, ButtonSize, ButtonStyle } from '../button' +import { Button } from '../button' import { Sort } from '../pagination' import '../styles/_includes.scss' import { IconOutline } from '../svgs' @@ -16,13 +16,10 @@ import styles from './Table.module.scss' interface TableProps { readonly columns: ReadonlyArray> readonly data: ReadonlyArray - readonly loadMoreBtnLabel?: string - readonly loadMoreBtnSize?: ButtonSize - readonly loadMoreBtnStyle?: ButtonStyle readonly moreToLoad?: boolean - readonly onLoadMoreClick?: (data: T) => void + readonly onLoadMoreClick?: () => void readonly onRowClick?: (data: T) => void - readonly onToggleSort?: (sort: Sort | undefined) => void + readonly onToggleSort?: (sort: Sort) => void } interface DefaultSortDirectionMap { @@ -41,7 +38,7 @@ const Table: (props: TableProps) = Dispatch> ] = useState() - const [sortedData, setSortData]: [ReadonlyArray, Dispatch>>] + const [sortedData, setSortedData]: [ReadonlyArray, Dispatch>>] = useState>(props.data) useEffect(() => { @@ -54,7 +51,11 @@ const Table: (props: TableProps) = setDefaultSortDirectionMap(map) } - setSortData(tableGetSorted(data, columns, sort)) + // if we have a sort handler, don't worry about getting the sorted data; + // otherwise, get the sorted data for the table + const sorted: ReadonlyArray = !!props.onToggleSort ? data : tableGetSorted(data, columns, sort) + + setSortedData(sorted) }, [ columns, @@ -84,9 +85,7 @@ const Table: (props: TableProps) = setSort(newSort) // call the callback to notify parent for sort update - if (props.onToggleSort) { - props.onToggleSort(newSort) - } + props.onToggleSort?.(newSort) } const headerRow: Array = props.columns @@ -95,13 +94,12 @@ const Table: (props: TableProps) = const isCurrentlySorted: boolean = isSortable && col.propertyName === sort?.fieldName const colorClass: string = isCurrentlySorted ? 'black-100' : 'black-60' const sortableClass: string | undefined = isSortable ? styles.sortable : undefined - const centerClass: string | undefined = col.centerHeader ? styles.centerHeader : undefined return (
-
+
{col.label} {!!col.tooltip && (
@@ -172,9 +170,16 @@ const Table: (props: TableProps) =
{ - props.moreToLoad &&
-
+ !!props.moreToLoad && !!props.onLoadMoreClick && ( +
+
+ ) }
) diff --git a/src-ts/lib/table/index.ts b/src-ts/lib/table/index.ts index d7b124c44..396d852ea 100644 --- a/src-ts/lib/table/index.ts +++ b/src-ts/lib/table/index.ts @@ -1,2 +1,3 @@ export * from './table-column.model' +export { tableGetDefaultSort } from './table-functions' export { default as Table } from './Table' diff --git a/src-ts/lib/table/table-column.model.ts b/src-ts/lib/table/table-column.model.ts index 6d7ddb0c9..4323da523 100644 --- a/src-ts/lib/table/table-column.model.ts +++ b/src-ts/lib/table/table-column.model.ts @@ -1,7 +1,6 @@ import { TableCellType } from './table-cell.type' export interface TableColumn { - readonly centerHeader?: boolean readonly defaultSortDirection?: 'asc' | 'desc' readonly isDefaultSort?: boolean readonly label?: string diff --git a/src-ts/lib/table/table-functions/table.functions.ts b/src-ts/lib/table/table-functions/table.functions.ts index cfd4d25af..72e050f05 100644 --- a/src-ts/lib/table/table-functions/table.functions.ts +++ b/src-ts/lib/table/table-functions/table.functions.ts @@ -1,17 +1,21 @@ import { Sort } from '../../pagination' import { TableColumn } from '../table-column.model' -export function getDefaultSort(columns: ReadonlyArray>): Sort | undefined { +export function getDefaultSort(columns: ReadonlyArray>): Sort { const defaultSortColumn: TableColumn | undefined = columns.find(col => col.isDefaultSort) || columns.find(col => !!col.propertyName) + || columns?.[0] - const defaultSort: Sort | undefined = !defaultSortColumn?.propertyName - ? undefined - : { - direction: defaultSortColumn.defaultSortDirection || 'asc', - fieldName: defaultSortColumn.propertyName, - } + // if we didn't find a default sort, we have a problem + if (!defaultSortColumn) { + throw new Error('A table must have at least one column.') + } + + const defaultSort: Sort = { + direction: defaultSortColumn.defaultSortDirection || 'asc', + fieldName: defaultSortColumn.propertyName || '', + } return defaultSort } diff --git a/src-ts/tools/gamification-admin/config/gamification-config.model.ts b/src-ts/tools/gamification-admin/game-config/gamification-config.model.ts similarity index 75% rename from src-ts/tools/gamification-admin/config/gamification-config.model.ts rename to src-ts/tools/gamification-admin/game-config/gamification-config.model.ts index f090f1389..c1b0124fe 100644 --- a/src-ts/tools/gamification-admin/config/gamification-config.model.ts +++ b/src-ts/tools/gamification-admin/game-config/gamification-config.model.ts @@ -1,3 +1,4 @@ export interface GamificationConfigModel { ORG_ID: string + PAGE_SIZE: number } diff --git a/src-ts/tools/gamification-admin/config/gamification.config.ts b/src-ts/tools/gamification-admin/game-config/gamification.config.ts similarity index 100% rename from src-ts/tools/gamification-admin/config/gamification.config.ts rename to src-ts/tools/gamification-admin/game-config/gamification.config.ts diff --git a/src-ts/tools/gamification-admin/config/gamification.default.config.ts b/src-ts/tools/gamification-admin/game-config/gamification.default.config.ts similarity index 91% rename from src-ts/tools/gamification-admin/config/gamification.default.config.ts rename to src-ts/tools/gamification-admin/game-config/gamification.default.config.ts index aa7ad4626..b2c40e4d8 100644 --- a/src-ts/tools/gamification-admin/config/gamification.default.config.ts +++ b/src-ts/tools/gamification-admin/game-config/gamification.default.config.ts @@ -2,4 +2,5 @@ import { GamificationConfigModel } from './gamification-config.model' export const GamificationConfigDefault: GamificationConfigModel = { ORG_ID: '6052dd9b-ea80-494b-b258-edd1331e27a3', + PAGE_SIZE: 12, } diff --git a/src-ts/tools/gamification-admin/config/gamification.dev.config.ts b/src-ts/tools/gamification-admin/game-config/gamification.dev.config.ts similarity index 56% rename from src-ts/tools/gamification-admin/config/gamification.dev.config.ts rename to src-ts/tools/gamification-admin/game-config/gamification.dev.config.ts index 63bd27ddf..02fec4630 100644 --- a/src-ts/tools/gamification-admin/config/gamification.dev.config.ts +++ b/src-ts/tools/gamification-admin/game-config/gamification.dev.config.ts @@ -1,5 +1,6 @@ import { GamificationConfigModel } from './gamification-config.model' +import { GamificationConfigDefault } from './gamification.default.config' export const GamificationConfigDev: GamificationConfigModel = { - ORG_ID: '6052dd9b-ea80-494b-b258-edd1331e27a3', + ...GamificationConfigDefault, } diff --git a/src-ts/tools/gamification-admin/config/gamification.prod.config.ts b/src-ts/tools/gamification-admin/game-config/gamification.prod.config.ts similarity index 63% rename from src-ts/tools/gamification-admin/config/gamification.prod.config.ts rename to src-ts/tools/gamification-admin/game-config/gamification.prod.config.ts index 922edc652..e49185be0 100644 --- a/src-ts/tools/gamification-admin/config/gamification.prod.config.ts +++ b/src-ts/tools/gamification-admin/game-config/gamification.prod.config.ts @@ -1,5 +1,7 @@ import { GamificationConfigModel } from './gamification-config.model' +import { GamificationConfigDefault } from './gamification.default.config' export const GamificationConfigProd: GamificationConfigModel = { + ...GamificationConfigDefault, ORG_ID: 'e111f8df-6ac8-44d1-b4da-bb916f5e3425', } diff --git a/src-ts/tools/gamification-admin/config/index.ts b/src-ts/tools/gamification-admin/game-config/index.ts similarity index 100% rename from src-ts/tools/gamification-admin/config/index.ts rename to src-ts/tools/gamification-admin/game-config/index.ts diff --git a/src-ts/tools/gamification-admin/lib/models/badge.model.ts b/src-ts/tools/gamification-admin/game-lib/game-badge.model.ts similarity index 60% rename from src-ts/tools/gamification-admin/lib/models/badge.model.ts rename to src-ts/tools/gamification-admin/game-lib/game-badge.model.ts index c88efeb78..7c4c719b2 100644 --- a/src-ts/tools/gamification-admin/lib/models/badge.model.ts +++ b/src-ts/tools/gamification-admin/game-lib/game-badge.model.ts @@ -1,4 +1,5 @@ -export interface Badge { +// TODO: add factory to convert snake case property names to camel case +export interface GameBadge { active: boolean badge_description: string badge_image_url: string diff --git a/src-ts/tools/gamification-admin/game-lib/index.ts b/src-ts/tools/gamification-admin/game-lib/index.ts new file mode 100644 index 000000000..f9755858a --- /dev/null +++ b/src-ts/tools/gamification-admin/game-lib/index.ts @@ -0,0 +1,3 @@ +export * from './game-badge.model' +export * from './use-get-game-badges-page.hook' +export * from './game-badge.model' diff --git a/src-ts/tools/gamification-admin/game-lib/use-get-game-badges-page.hook.ts b/src-ts/tools/gamification-admin/game-lib/use-get-game-badges-page.hook.ts new file mode 100644 index 000000000..885d1af51 --- /dev/null +++ b/src-ts/tools/gamification-admin/game-lib/use-get-game-badges-page.hook.ts @@ -0,0 +1,30 @@ +import { EnvironmentConfig } from '../../../config' +import { InfinitePageDao, InfinitePageHandler, Sort, useGetInfinitePage } from '../../../lib' +import { GamificationConfig } from '../game-config' + +import { GameBadge } from './game-badge.model' + +export function useGetGameBadgesPage(sort: Sort): InfinitePageHandler { + + function getKey(index: number, previousPageData: InfinitePageDao): string | undefined { + + // reached the end + if (!!previousPageData && !previousPageData.rows.length) { + return undefined + } + + const params: Record = { + limit: `${GamificationConfig.PAGE_SIZE}`, + offset: `${index * GamificationConfig.PAGE_SIZE}`, + order_by: sort.fieldName, + order_type: sort.direction, + organization_id: GamificationConfig.ORG_ID, + } + + const badgeEndpointUrl: URL = new URL(`${EnvironmentConfig.API.V5}/gamification/badges?${new URLSearchParams(params)}`) + + return badgeEndpointUrl.toString() + } + + return useGetInfinitePage(getKey) +} diff --git a/src-ts/tools/gamification-admin/game-lib/useGamificationBreadcrumb.provider.tsx b/src-ts/tools/gamification-admin/game-lib/useGamificationBreadcrumb.provider.tsx new file mode 100644 index 000000000..274022b16 --- /dev/null +++ b/src-ts/tools/gamification-admin/game-lib/useGamificationBreadcrumb.provider.tsx @@ -0,0 +1,16 @@ +import { BreadcrumbItemModel } from '../../../lib' +import { basePath } from '../gamification-admin.routes' +import { toolTitle } from '../GamificationAdmin' + +export function useGamificationBreadcrumb(items: Array): Array { + + const breadcrumb: Array = [ + { + name: toolTitle, + url: basePath, + }, + ...items, + ] + + return breadcrumb +} diff --git a/src-ts/tools/gamification-admin/gamification-admin.routes.tsx b/src-ts/tools/gamification-admin/gamification-admin.routes.tsx index 24ee0b8c1..108d2cf53 100644 --- a/src-ts/tools/gamification-admin/gamification-admin.routes.tsx +++ b/src-ts/tools/gamification-admin/gamification-admin.routes.tsx @@ -5,8 +5,16 @@ import BadgeDetailPage from './pages/badge-detail/BadgeDetailPage' import BadgeListingPage from './pages/badge-listing/BadgeListingPage' import CreateBadgePage from './pages/create-badge/CreateBadgePage' -export const baseUrl: string = '/gamification-admin' -export const rolesRequired: Array = [UserRole.gamificationAdmin] +const baseDetailPath: string = '/badge-detail' +const createBadgePath: string = '/create-badge' + +export const basePath: string = '/gamification-admin' + +export function badgeDetailPath(badgeId: string, view?: 'edit' | 'award'): string { + return `${basePath}${baseDetailPath}/${badgeId}${!!view ? `#${view}` : ''}` +} + +export const createBadgeRoute: string = `${basePath}${createBadgePath}` export const gamificationAdminRoutes: Array = [ { @@ -18,17 +26,19 @@ export const gamificationAdminRoutes: Array = [ }, { element: , - route: '/create-badge', + route: createBadgePath, }, { element: , - route: '/badge-detail/:id', + route: `${baseDetailPath}/:id`, }, ], element: , hidden: true, - rolesRequired, - route: baseUrl, + rolesRequired: [ + UserRole.gamificationAdmin, + ], + route: basePath, title: toolTitle, }, ] diff --git a/src-ts/tools/gamification-admin/lib/hooks/getDataSource.ts b/src-ts/tools/gamification-admin/lib/hooks/getDataSource.ts deleted file mode 100644 index d81ffdcab..000000000 --- a/src-ts/tools/gamification-admin/lib/hooks/getDataSource.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { EnvironmentConfig } from '../../../../config' - -export default function getDataSource(): string { - return `${EnvironmentConfig.API.V5}/gamification` -} diff --git a/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx b/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx index 1e84dc1ed..5283989c4 100644 --- a/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx @@ -1,32 +1,34 @@ -import { FC, useMemo } from 'react' +import { FC } from 'react' import { Breadcrumb, BreadcrumbItemModel, ContentLayout } from '../../../../lib' -import { baseUrl } from '../../gamification-admin.routes' -import { toolTitle } from '../../GamificationAdmin' +import { useGamificationBreadcrumb } from '../../game-lib' import styles from './BadgeDetailPage.module.scss' const BadgeDetailPage: FC = () => { - // TDOD: use whit GAME-78 - // const { id: badgeID } : { badgeID: string } = useParams() - const breadcrumb: Array = useMemo(() => [ - { name: toolTitle, url: baseUrl }, - { name: 'badge detail', url: '#' }, - ], []) + // TDOD: use whit GAME-78 + // const { id: badgeID } : { badgeID: string } = useParams() - return ( - - -
+ const breadcrumb: Array = useGamificationBreadcrumb([ + { + name: 'badge detail', + url: '#', + }, + ]) -
-
- ) + return ( + + +
+ +
+
+ ) } export default BadgeDetailPage diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx index 08dc7c2be..1e192bd60 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx @@ -1,77 +1,64 @@ -import { flatten, map } from 'lodash' import { Dispatch, FC, SetStateAction, useState } from 'react' import { NavigateFunction, useNavigate } from 'react-router-dom' -// tslint:disable-next-line -import useSWRInfinite from 'swr/infinite' -import { ButtonProps, ContentLayout, LoadingSpinner, Sort, Table, TableColumn } from '../../../../lib' -import { GamificationConfig } from '../../config' -import { baseUrl } from '../../gamification-admin.routes' -import getDataSource from '../../lib/hooks/getDataSource' -import { Badge } from '../../lib/models/badge.model' +import { + ButtonProps, + ContentLayout, + InfinitePageHandler, + LoadingSpinner, + Sort, + Table, + TableColumn, + tableGetDefaultSort +} from '../../../../lib' +import { GameBadge, useGetGameBadgesPage } from '../../game-lib' +import { createBadgeRoute } from '../../gamification-admin.routes' -import { badgeListingColumns } from './badge-listing-table/badge-listing-table.config' +import { badgeListingColumns } from './badge-listing-table' import styles from './BadgeListingPage.module.scss' const BadgeListingPage: FC = () => { - const [order, setOrder]: any = useState({ by: 'badge_name', type: 'asc' }) - const navigate: NavigateFunction = useNavigate() - const dataSource: string = getDataSource() - // server-side pagination hook - const getKey: any = (pageIndex: any, previousPageData: any) => { - if (previousPageData && !previousPageData.rows.length) { return undefined } // reached the end - return `${dataSource}/badges?organization_id=${GamificationConfig.ORG_ID}&limit=12&offset=${pageIndex * 12}&order_by=${order.by}&order_type=${order.type}` - } - const { data: badges, size, setSize }: any = useSWRInfinite(getKey, { revalidateFirstPage: false }) + const [sort, setSort]: [Sort, Dispatch>] = useState(tableGetDefaultSort(badgeListingColumns)) + const [columns]: [ + ReadonlyArray>, + Dispatch>>>, + ] + = useState>>([...badgeListingColumns]) - const tableData: Array = flatten(map(badges, page => page.rows)) // flatten version of badges paginated data - const loadedCnt: any = badges?.reduce((ps: any, a: any) => ps + a.rows.length, 0) // how much data is loaded so far + const gameBadgeDataHandler: InfinitePageHandler = useGetGameBadgesPage(sort) + const navigate: NavigateFunction = useNavigate() - // listing table config - const [columns]: [ - ReadonlyArray>, - Dispatch>>>, - ] - = useState>>([...badgeListingColumns]) + function onSortClick(newSort: Sort): void { + setSort({ ...newSort }) + } - // on sort toggle callback - const onOrderClick: any = (sort: Sort) => { - setOrder({ - by: sort.fieldName, - type: sort.direction, - }) - } + // header button config + const buttonConfig: ButtonProps = { + label: 'Create New Badge', + onClick: () => navigate(createBadgeRoute), + } - // on load more callback - const onLoadMoreClick: any = () => setSize(size + 1) - // header button config - const buttonConfig: ButtonProps = { - label: 'Create New Badge', - onClick: () => navigate(`${baseUrl}/create-badge`), - } + if (!gameBadgeDataHandler.data) { + return + } - if (!badges) { return } - - return ( - -
- - - - ) + return ( + +
+
+ + + ) } export default BadgeListingPage diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.tsx index 33972e587..6ca456669 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-action-renderer/BadgeActionRenderer.tsx @@ -1,19 +1,49 @@ -import { Button, useCheckIsMobile } from '../../../../../../lib' -import { baseUrl } from '../../../../gamification-admin.routes' -import { Badge } from '../../../../lib/models/badge.model' +import { Button, ButtonProps, useCheckIsMobile } from '../../../../../../lib' +import { GameBadge } from '../../../../game-lib' +import { badgeDetailPath } from '../../../../gamification-admin.routes' import styles from './BadgeActionRenderer.module.scss' -function BadgeActionRenderer(badge: Badge): JSX.Element { - const isMobile: boolean = useCheckIsMobile() +function BadgeActionRenderer(badge: GameBadge): JSX.Element { - return ( -
-
- ) + const isMobile: boolean = useCheckIsMobile() + + const buttonProps: ButtonProps = { + buttonStyle: 'secondary', + size: isMobile ? 'xs' : 'sm', + } + + const actionButtons: Array<{ + label: string + view?: 'edit' | 'award' + }> = [ + { + label: 'View', + }, + { + label: 'Edit', + view: 'edit', + }, + { + label: 'Award', + view: 'award', + }, + ] + + return ( +
+ {actionButtons.map((button, index) => { + return ( +
+ ) } export default BadgeActionRenderer diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-listing-table.config.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-listing-table.config.tsx index ab9667ebf..1d6d54ef4 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-listing-table.config.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-listing-table.config.tsx @@ -1,10 +1,10 @@ import { TableColumn } from '../../../../../lib' -import { Badge } from '../../../lib/models/badge.model' +import { GameBadge } from '../../../game-lib' import { BadgeActionRenderer } from './badge-action-renderer' import { BadgeListingNameRenderer } from './badge-name-renderer' -export const badgeListingColumns: ReadonlyArray> = [ +export const badgeListingColumns: ReadonlyArray> = [ { defaultSortDirection: 'asc', isDefaultSort: true, @@ -14,8 +14,6 @@ export const badgeListingColumns: ReadonlyArray> = [ type: 'element', }, { - centerHeader: true, - label: 'Actions', renderer: BadgeActionRenderer, type: 'action', }, diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.tsx index 333aed2e7..7b9c604ca 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/badge-name-renderer/BadgeListingNameRenderer.tsx @@ -1,11 +1,15 @@ -import { Badge } from '../../../../lib/models/badge.model' +import { GameBadge } from '../../../../game-lib' import styles from './BadgeListingNameRenderer.module.scss' -function BadgeListingNameRenderer(badge: Badge): JSX.Element { +function BadgeListingNameRenderer(badge: GameBadge): JSX.Element { return (
- {badge.badge_name} + {badge.badge_name}

{badge.badge_name}

) diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/index.ts b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/index.ts new file mode 100644 index 000000000..8fa32ec69 --- /dev/null +++ b/src-ts/tools/gamification-admin/pages/badge-listing/badge-listing-table/index.ts @@ -0,0 +1 @@ +export * from './badge-listing-table.config' diff --git a/src-ts/tools/gamification-admin/pages/create-badge/CreateBadgePage.tsx b/src-ts/tools/gamification-admin/pages/create-badge/CreateBadgePage.tsx index 020b7f8eb..22d7e59d6 100644 --- a/src-ts/tools/gamification-admin/pages/create-badge/CreateBadgePage.tsx +++ b/src-ts/tools/gamification-admin/pages/create-badge/CreateBadgePage.tsx @@ -1,30 +1,32 @@ -import { FC, useMemo } from 'react' +import { FC } from 'react' import { Breadcrumb, BreadcrumbItemModel, ContentLayout } from '../../../../lib' -import { baseUrl } from '../../gamification-admin.routes' -import { toolTitle } from '../../GamificationAdmin' +import { useGamificationBreadcrumb } from '../../game-lib' import styles from './CreateBadgePage.module.scss' const CreateBadgePage: FC = () => { - const breadcrumb: Array = useMemo(() => [ - { name: toolTitle, url: baseUrl }, - { name: 'create badge', url: '#' }, - ], []) - return ( - - -
+ const breadcrumb: Array = useGamificationBreadcrumb([ + { + name: 'create badge', + url: '#', + }, + ]) -
-
- ) + return ( + + +
+ +
+
+ ) } export default CreateBadgePage From 95cefd191d7fd777a194ed0c27124e7d8a2b439e Mon Sep 17 00:00:00 2001 From: Brooke Date: Mon, 19 Sep 2022 15:55:06 -0700 Subject: [PATCH 7/8] GAME-107 clean-up --- src-ts/tools/gamification-admin/game-lib/index.ts | 2 +- ...dcrumb.provider.tsx => use-gamification-breadcrumb.hook.tsx} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src-ts/tools/gamification-admin/game-lib/{useGamificationBreadcrumb.provider.tsx => use-gamification-breadcrumb.hook.tsx} (100%) diff --git a/src-ts/tools/gamification-admin/game-lib/index.ts b/src-ts/tools/gamification-admin/game-lib/index.ts index f9755858a..6cb57fe53 100644 --- a/src-ts/tools/gamification-admin/game-lib/index.ts +++ b/src-ts/tools/gamification-admin/game-lib/index.ts @@ -1,3 +1,3 @@ export * from './game-badge.model' export * from './use-get-game-badges-page.hook' -export * from './game-badge.model' +export * from './use-gamification-breadcrumb.hook' diff --git a/src-ts/tools/gamification-admin/game-lib/useGamificationBreadcrumb.provider.tsx b/src-ts/tools/gamification-admin/game-lib/use-gamification-breadcrumb.hook.tsx similarity index 100% rename from src-ts/tools/gamification-admin/game-lib/useGamificationBreadcrumb.provider.tsx rename to src-ts/tools/gamification-admin/game-lib/use-gamification-breadcrumb.hook.tsx From 5ac9f54ee24956ee4db9aabb1da7de41e29ce90b Mon Sep 17 00:00:00 2001 From: Brooke Date: Mon, 19 Sep 2022 16:09:52 -0700 Subject: [PATCH 8/8] GAMe-107 clean up --- src-ts/lib/pagination/infinite-page-dao.model.ts | 1 + .../pages/badge-listing/BadgeListingPage.tsx | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src-ts/lib/pagination/infinite-page-dao.model.ts b/src-ts/lib/pagination/infinite-page-dao.model.ts index 2b2520095..ae1ca01da 100644 --- a/src-ts/lib/pagination/infinite-page-dao.model.ts +++ b/src-ts/lib/pagination/infinite-page-dao.model.ts @@ -1,4 +1,5 @@ export interface InfinitePageDao { count: number + // TODO: rename this 'items' so it can be used in a grid/card view rows: ReadonlyArray } diff --git a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx index 1e192bd60..dfa788084 100644 --- a/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx +++ b/src-ts/tools/gamification-admin/pages/badge-listing/BadgeListingPage.tsx @@ -26,7 +26,7 @@ const BadgeListingPage: FC = () => { ] = useState>>([...badgeListingColumns]) - const gameBadgeDataHandler: InfinitePageHandler = useGetGameBadgesPage(sort) + const pageHandler: InfinitePageHandler = useGetGameBadgesPage(sort) const navigate: NavigateFunction = useNavigate() function onSortClick(newSort: Sort): void { @@ -39,7 +39,7 @@ const BadgeListingPage: FC = () => { onClick: () => navigate(createBadgeRoute), } - if (!gameBadgeDataHandler.data) { + if (!pageHandler.data) { return } @@ -51,9 +51,9 @@ const BadgeListingPage: FC = () => {