Skip to content

Commit 114e42e

Browse files
authored
Merge pull request #193 from CivicDataLab/177-dashboard-to-reflect-the-logo-and-details-of-the-entity
177 dashboard to reflect the logo and details of the entity
2 parents 651c75b + 6d2d672 commit 114e42e

File tree

8 files changed

+182
-89
lines changed

8 files changed

+182
-89
lines changed

.github/workflows/pre-merge.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ env:
1515
END_SESSION_URL: ${{secrets.END_SESSION_URL}}
1616
REFRESH_TOKEN_URL: ${{secrets.REFRESH_TOKEN_URL}}
1717
NEXT_PUBLIC_BACKEND_URL: ${{secrets.NEXT_PUBLIC_BACKEND_URL_DS}}
18+
BACKEND_URL: ${{secrets.BACKEND_URL}}
1819
BACKEND_GRAPHQL_URL: ${{secrets.BACKEND_GRAPHQL_URL_DS}}
1920
NEXT_PUBLIC_ENABLE_ACCESSMODEL: ${{secrets.NEXT_PUBLIC_ENABLE_ACCESSMODEL_DS}}
2021
NEXT_PUBLIC_BACKEND_GRAPHQL_URL: ${{secrets.NEXT_PUBLIC_BACKEND_GRAPHQL_URL_DS}}
21-
22+
2223
jobs:
2324
build:
2425
runs-on: ubuntu-latest

app/[locale]/dashboard/[entityType]/[entitySlug]/layout.tsx

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
import React from 'react';
44
import { notFound, useParams } from 'next/navigation';
55
import { SidebarNavItem } from '@/types';
6+
import { useQuery } from '@tanstack/react-query';
67

8+
import { GraphQL } from '@/lib/api';
79
import { cn } from '@/lib/utils';
810
import BreadCrumbs from '@/components/BreadCrumbs';
911
import { DashboardNav } from '../../components/dashboard-nav';
1012
import { MobileDashboardNav } from '../../components/mobile-dashboard-nav';
1113
import styles from '../../components/styles.module.scss';
14+
import { getDataSpaceDetailsQryDoc, getOrgDetailsQryDoc } from './schema';
1215

1316
interface DashboardLayoutProps {
1417
children?: React.ReactNode;
@@ -18,6 +21,17 @@ export default function OrgDashboardLayout({ children }: DashboardLayoutProps) {
1821
const [isOpened, setIsOpened] = React.useState(false);
1922
const params = useParams<{ entityType: string; entitySlug: string }>();
2023

24+
const EntityDetailsQryRes: { data: any; isLoading: boolean; error: any } =
25+
useQuery([`entity_details_${params.entityType}`], () =>
26+
GraphQL(
27+
params.entityType === 'organization'
28+
? getOrgDetailsQryDoc
29+
: getDataSpaceDetailsQryDoc,
30+
{},
31+
{ filters: { slug: params.entitySlug } }
32+
)
33+
);
34+
2135
if (
2236
process.env.NEXT_PUBLIC_DATASPACE_FEATURE_ENABLED !== 'true' &&
2337
params.entityType === 'dataspace'
@@ -56,7 +70,11 @@ export default function OrgDashboardLayout({ children }: DashboardLayoutProps) {
5670
},
5771
{
5872
href: '',
59-
label: `${params.entitySlug}`,
73+
label:
74+
(params.entityType === 'organization'
75+
? EntityDetailsQryRes.data?.organisations[0]
76+
: EntityDetailsQryRes.data?.dataspaces[0]
77+
)?.name || params.entitySlug,
6078
},
6179
]}
6280
/>
@@ -66,7 +84,14 @@ export default function OrgDashboardLayout({ children }: DashboardLayoutProps) {
6684
' bg-surfaceDefault p-4 md:flex'
6785
)}
6886
>
69-
<DashboardNav items={orgSidebarNav} entitySlug={params.entitySlug} />
87+
<DashboardNav
88+
items={orgSidebarNav}
89+
entityDetails={
90+
params.entityType === 'organization'
91+
? EntityDetailsQryRes.data?.organisations[0]
92+
: EntityDetailsQryRes.data?.dataspaces[0]
93+
}
94+
/>
7095

7196
<div className="z-1 basis-2 md:hidden">
7297
<MobileDashboardNav
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { graphql } from '@/gql';
2+
3+
export const getOrgDetailsQryDoc: any = graphql(`
4+
query getOrgDetailsQry($filters: OrganizationFilter) {
5+
organisations(filters: $filters) {
6+
id
7+
name
8+
logo {
9+
name
10+
path
11+
size
12+
url
13+
width
14+
height
15+
}
16+
slug
17+
}
18+
}
19+
`);
20+
21+
export const getDataSpaceDetailsQryDoc: any = graphql(`
22+
query getDataSpaceDetailsQry($filters: DataSpaceFilter) {
23+
dataspaces(filters: $filters) {
24+
id
25+
name
26+
logo {
27+
name
28+
path
29+
size
30+
url
31+
width
32+
height
33+
}
34+
slug
35+
}
36+
}
37+
`);
Lines changed: 63 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client';
22

3+
import { useState } from 'react';
34
import Image from 'next/image';
45
import Link from 'next/link';
56
import { notFound, useParams, usePathname } from 'next/navigation';
@@ -20,41 +21,20 @@ const Page = () => {
2021

2122
const params = useParams<{ entityType: string }>();
2223

23-
const allOrganizationsList: {
24+
const allEntitiesList: {
2425
data: any;
2526
isLoading: boolean;
2627
error: any;
2728
isError: boolean;
28-
} = useQuery([`all_organizations_list_page`], () =>
29+
} = useQuery([`all_enitites_list_${params.entityType}`], () =>
2930
GraphQL(
30-
allOrganizationsListingDoc,
31+
params.entityType === 'organization'
32+
? allOrganizationsListingDoc
33+
: allDataSpacesListingDoc,
3134
{
3235
// Entity Headers if present
3336
},
34-
{
35-
options: {
36-
skip: params.entityType !== 'organization',
37-
},
38-
}
39-
)
40-
);
41-
42-
const allDataSpacesList: {
43-
data: any;
44-
isLoading: boolean;
45-
error: any;
46-
isError: boolean;
47-
} = useQuery([`all_dataspaces_list_page`], () =>
48-
GraphQL(
49-
allDataSpacesListingDoc,
50-
{
51-
// Entity Headers if present
52-
},
53-
{
54-
options: {
55-
skip: params.entityType !== 'dataspace',
56-
},
57-
}
37+
[]
5838
)
5939
);
6040

@@ -88,48 +68,21 @@ const Page = () => {
8868
</div>
8969
<div className="m-auto flex w-11/12 flex-col">
9070
<DashboardHeader currentPath={pathname} />
91-
{allDataSpacesList.isLoading || allOrganizationsList.isLoading ? (
71+
{allEntitiesList.isLoading ? (
9272
<LoadingPage />
9373
) : (
9474
<div className={cn(styles.Main)}>
9575
<div className="flex flex-wrap gap-24">
9676
{[
9777
...(params.entityType === 'organization'
98-
? allOrganizationsList.data.organisations
99-
: allDataSpacesList.data.dataspaces),
100-
]?.map((orgItem) => (
101-
<div
102-
key={orgItem.slug}
103-
className="flex max-w-64 flex-col items-center gap-3 rounded-2 border-2 border-solid border-baseGraySlateSolid4 px-4 py-5 text-center"
104-
>
105-
<Link
106-
href={`/dashboard/${params.entityType}/${orgItem.slug}/dataset`}
107-
id={orgItem.slug}
108-
>
109-
<div className="border-var(--border-radius-5) rounded-2 ">
110-
<Image
111-
src={'/obi.jpg'}
112-
width={200}
113-
height={200}
114-
alt={'Organization Logo'}
115-
/>
116-
</div>
117-
118-
{/* <LinkButton
119-
href={`/dashboard/organization/${orgItem.slug}/dataset`}
120-
>
121-
Manage Datasets
122-
</LinkButton>
123-
<LinkButton
124-
href={`/dashboard/organization/${orgItem.slug}/consumers`}
125-
>
126-
Manage Consumers
127-
</LinkButton> */}
128-
</Link>
129-
<div>
130-
<Text variant="headingMd">{orgItem.name}</Text>
131-
</div>
132-
</div>
78+
? allEntitiesList.data.organisations
79+
: allEntitiesList.data.dataspaces),
80+
]?.map((entityItem) => (
81+
<EntityCard
82+
key={entityItem.slug}
83+
entityItem={entityItem}
84+
params={params}
85+
/>
13386
))}
13487
<div className="flex h-72 w-56 flex-col items-center justify-center gap-3 rounded-2 bg-baseGraySlateSolid6 p-4">
13588
<Icon source={Icons.plus} size={40} color="success" />
@@ -146,3 +99,50 @@ const Page = () => {
14699
};
147100

148101
export default Page;
102+
103+
const EntityCard = ({ key, entityItem, params }: any) => {
104+
const [isImageValid, setIsImageValid] = useState(() => {
105+
return entityItem.logo ? true : false;
106+
});
107+
return (
108+
<div
109+
key={key}
110+
className="flex h-72 w-56 flex-col items-center gap-3 rounded-2 border-2 border-solid border-baseGraySlateSolid4 px-4 py-5 text-center"
111+
>
112+
<div className="flex h-full w-full items-center justify-center rounded-2">
113+
<Link
114+
href={`/dashboard/${params.entityType}/${entityItem.slug}/dataset`}
115+
id={entityItem.slug}
116+
>
117+
<div className="border-var(--border-radius-5) rounded-2">
118+
{isImageValid ? (
119+
<Image
120+
height={160}
121+
width={160}
122+
src={`${process.env.NEXT_PUBLIC_BACKEND_URL}${entityItem.logo.url}`}
123+
alt={`${entityItem.name} logo`}
124+
onError={() => {
125+
setIsImageValid(false);
126+
}}
127+
className="object-contain"
128+
/>
129+
) : (
130+
<Image
131+
height={160}
132+
width={160}
133+
src={'/fallback.svg'}
134+
alt={`fallback logo`}
135+
className="fill-current object-contain text-baseGraySlateSolid6"
136+
/>
137+
)}
138+
</div>
139+
</Link>
140+
</div>
141+
<div>
142+
<Text variant="headingMd" className="text-center">
143+
{entityItem.name}
144+
</Text>
145+
</div>
146+
</div>
147+
);
148+
};

app/[locale]/dashboard/components/dashboard-nav.tsx

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import React from 'react';
3+
import { useEffect, useState } from 'react';
44
import Image from 'next/image';
55
import Link from 'next/link';
66
import { usePathname } from 'next/navigation';
@@ -17,11 +17,26 @@ interface DashboardNavProps {
1717
}
1818
export function DashboardNav({
1919
items,
20-
entitySlug,
21-
}: DashboardNavProps & { entitySlug?: string }) {
22-
const [isCollapsed, setIsCollapsed] = React.useState(false);
20+
entityDetails,
21+
}: DashboardNavProps & { entityDetails?: any }) {
22+
const [isCollapsed, setIsCollapsed] = useState(false);
23+
24+
const [isImageValid, setIsImageValid] = useState(() => {
25+
return entityDetails?.logo ? true : false;
26+
});
2327
const path = usePathname();
2428

29+
useEffect(() => {
30+
if (
31+
entityDetails &&
32+
(typeof entityDetails.logo === 'undefined' || entityDetails.logo === null)
33+
) {
34+
setIsImageValid(false);
35+
} else {
36+
setIsImageValid(true);
37+
}
38+
}, [entityDetails]);
39+
2540
useMetaKeyPress('b', () => setIsCollapsed((e) => !e));
2641

2742
if (items && !items.length) {
@@ -39,17 +54,31 @@ export function DashboardNav({
3954
)}
4055
>
4156
<nav className={cn('flex flex-col gap-2')}>
42-
{entitySlug && !isCollapsed ? (
57+
{entityDetails && !isCollapsed ? (
4358
<>
4459
<div className="flex flex-col items-center justify-center px-4 py-8">
45-
<Image
46-
height={140}
47-
width={140}
48-
src={'/obi.jpg'}
49-
alt={'Organisation ID'}
50-
/>
60+
{isImageValid ? (
61+
<Image
62+
height={140}
63+
width={140}
64+
src={`${process.env.NEXT_PUBLIC_BACKEND_URL}${entityDetails?.logo?.url}`}
65+
alt={`${entityDetails?.name} logo`}
66+
onError={() => {
67+
setIsImageValid(false);
68+
}}
69+
className="object-contain"
70+
/>
71+
) : (
72+
<Image
73+
height={140}
74+
width={140}
75+
src={'/fallback.svg'}
76+
alt={'fallback logo'}
77+
className="fill-current bg-baseGraySlateSolid6 object-contain text-baseGraySlateSolid6"
78+
/>
79+
)}
5180
<Text variant="headingMd" fontWeight="medium" className="py-2">
52-
{entitySlug}
81+
{entityDetails?.name}
5382
</Text>
5483
<Link href={'/dashboard'}>
5584
<Text variant="headingXs" color="interactive">

app/[locale]/manage/layout.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use client';
22

33
import React from 'react';
4-
import { useParams } from 'next/navigation';
54
import { SidebarNavItem } from '@/types';
65

76
import { cn } from '@/lib/utils';
@@ -18,8 +17,6 @@ interface DashboardLayoutProps {
1817
export default function OrgDashboardLayout({ children }: DashboardLayoutProps) {
1918
const [isOpened, setIsOpened] = React.useState(false);
2019

21-
const params = useParams<{ organizationId: string }>();
22-
2320
const orgSidebarNav: Array<SidebarNavItem> = [
2421
{
2522
title: 'Use Cases',
@@ -28,8 +25,6 @@ export default function OrgDashboardLayout({ children }: DashboardLayoutProps) {
2825
},
2926
];
3027

31-
const organizationId = params.organizationId;
32-
3328
return (
3429
<React.Suspense fallback={<LoadingPage />}>
3530
<BreadCrumbs
@@ -47,7 +42,7 @@ export default function OrgDashboardLayout({ children }: DashboardLayoutProps) {
4742
' bg-surfaceDefault p-4 md:flex'
4843
)}
4944
>
50-
<DashboardNav items={orgSidebarNav} entitySlug={organizationId} />
45+
<DashboardNav items={orgSidebarNav} />
5146

5247
<div className="z-1 basis-2 md:hidden">
5348
<MobileDashboardNav

0 commit comments

Comments
 (0)