Skip to content

Commit

Permalink
feat: show organisation metadata using ror api
Browse files Browse the repository at this point in the history
  • Loading branch information
dmijatovic committed Oct 20, 2022
1 parent 595ad3f commit 6a25f52
Show file tree
Hide file tree
Showing 6 changed files with 254 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -143,25 +143,17 @@ export default function OrganisationLogo({id,name,website,logo_id,isMaintainer}:
)
}

// for the users we add link to organisation website (if present)
// for the maintainers click on the logo opens the image upload
function renderLogo() {
if (website) {
return (
<Link href={website} passHref>
<a target="_blank">
{renderAvatar()}
</a>
</Link>
)
}
return renderAvatar()
}
if (isMaintainer) {
return (
<div className="py-[4rem] flex relative">
{renderAvatar()}
<div className="absolute flex justify-start left-2 bottom-1">
<div className="pt-12 pb-2 flex relative">
<div className="">
{renderAvatar()}
</div>
<div style={{
position: 'absolute',
top: '0rem',
right: '0rem'
}}>
<label htmlFor="upload-avatar-image"
// style={{cursor:'pointer'}}
title="Click to upload an image"
Expand Down Expand Up @@ -196,9 +188,5 @@ export default function OrganisationLogo({id,name,website,logo_id,isMaintainer}:
)
}

return (
<div className='hidden md:block md:py-[3rem]'>
{renderLogo()}
</div>
)
return renderAvatar()
}
189 changes: 189 additions & 0 deletions frontend/components/organisation/metadata/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import Link from 'next/link'
import {RORItem} from '~/utils/getROR'
import OrganisationLogo from './OrganisationLogo'
import PlaceIcon from '@mui/icons-material/Place'
import Chip from '@mui/material/Chip'
import {OrganisationForOverview} from '~/types/Organisation'

type OrgnisationInfoProps = {
organisation: OrganisationForOverview,
meta: RORItem|null,
isMaintainer: boolean
}

export function UnderlinedTitle({title}:{title: string}) {
return (
<>
<h4 className="pt-2 text-base-content-disabled">{title}</h4>
<hr className="pb-2" />
</>
)
}

export function RorLocation({meta}: { meta: RORItem | null }) {
try {
if (meta===null) return null
const location = meta.addresses[0]
if (location) {
const country = meta.country.country_name
const {lng,lat} = location
if (lng && lat) {
const query = encodeURIComponent(`${meta.name},${location.city},${country}`)
return (
<>
<UnderlinedTitle title='Location' />
<Link
href={`https://www.google.com/maps/search/?api=1&query=${query}`}
passHref
>
<a target="_blank">
<div className="flex gap-2">
<PlaceIcon sx={{
width: '1.5rem',
height:'1.5rem'
}} />
<div>
<div>{meta.name}</div>
<div>{location.city}, {country}</div>
</div>
</div>
</a>
</Link>
</>
)
}
return null
}
return null
} catch (e) {
return null
}
}

export function Links({links=[]}:{links:string[]}) {
try {
if (links.length===0) return null
return (
<>
<UnderlinedTitle title='Links' />
{links.map(item => (
<Link
key={item}
href={item}
passHref
>
<a target="_blank">
<div
title={item}
style={{
overflow: 'hidden',
textOverflow:'ellipsis'
}}>{item}</div>
</a>
</Link>
))}
</>
)
} catch (e) {
return null
}
}

export function RorTypes({meta}:{meta:RORItem|null}) {
try {
if (meta===null) return null
return (
<>
<UnderlinedTitle title='Type' />
<div className="flex">
{meta.types.map(item => (
<Chip
key={item}
title={item}
label={item}
sx={{
marginBottom: '1rem',
marginRight: '0.5rem',
maxWidth: '19rem',
borderRadius: '0rem 0.5rem',
backgroundColor: 'primary.main',
color: 'primary.contrastText',
textTransform: 'uppercase',
letterSpacing: '0.125rem'
}}
/>
))}
</div>
</>
)
} catch (e) {
return null
}
}


export default function OrganisationMetadata({organisation, meta, isMaintainer}: OrgnisationInfoProps) {

function getAllLinks() {
const links:string[] = []
if (organisation.website) {
// website as first link
links.push(organisation.website)
}
if (meta && meta.links) {
meta.links.forEach(item => {
// add only new items
if (links.indexOf(item) === -1) {
links.push(item)
}
})
}
// meta.id is ror_id url
if (meta && meta.id && links.indexOf(meta.id) === -1) {
// add only new items
links.push(meta.id)
}
// some organisations provide wikipedia page
if (meta && meta?.wikipedia_url && links.indexOf(meta?.wikipedia_url) === -1) {
links.push(meta?.wikipedia_url)
}
return links
}

function renderInfo() {
// if no metadata but website is provided
if (meta === null && organisation.website) {
// we return one link
return (
<Links links={[organisation.website]} />
)
} else if (meta) {
// if ror_id is valid (meta is present) we
// merge all links from meta and organisation.website
const links = getAllLinks()
return (
<>
<RorTypes meta={meta} />
<RorLocation meta={meta} />
<Links links={links} />
</>
)
}
// if no meta and no website we return nothing
return null
}

return (
<div className="my-8 p-6 border min-h-[9rem] max-w-[20rem]"
style={{
borderRadius:'0rem 2rem'
}}
>
<OrganisationLogo
isMaintainer={isMaintainer}
{...organisation}
/>
{renderInfo()}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {useEffect, useState} from 'react'
import {getOrganisationMetadata, RORItem} from '~/utils/getROR'

export function useOrganisationmMetadata(ror_id: string|null) {
const [meta, setMeta] = useState <RORItem|null>(null)
const [loading, setLoading] = useState(true)

useEffect(() => {
async function getMeta() {
const resp = await getOrganisationMetadata(ror_id)
setMeta(resp)
setLoading(false)
}
if (ror_id) {
getMeta()
}
},[ror_id])

return {
meta,
loading
}
}
15 changes: 10 additions & 5 deletions frontend/pages/organisations/[...slug].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {app} from '../../config/app'
import useOrganisationMaintainer from '../../auth/permissions/useOrganisationMaintainer'
import DefaultLayout from '../../components/layout/DefaultLayout'
import {getOrganisationBySlug} from '../../utils/getOrganisations'
import OrganisationLogo from '../../components/organisation/settings/OrganisationLogo'
import OrganisationMetadata from '../../components/organisation/metadata'
import ContentLoader from '../../components/layout/ContentLoader'
import OrganisationNav from '../../components/organisation/OrganisationNav'
import {organisationMenu, OrganisationMenuProps} from '../../components/organisation/OrganisationNavItems'
Expand All @@ -20,14 +20,16 @@ import {OrganisationForOverview} from '../../types/Organisation'

import {SearchProvider} from '../../components/search/SearchContext'
import {PaginationProvider} from '../../components/pagination/PaginationContext'
import {getOrganisationMetadata, RORItem} from '~/utils/getROR'

export type OrganisationPageProps = {
organisation: OrganisationForOverview,
ror: RORItem | null
slug: string[],
page: string
}

export default function OrganisationPage({organisation,slug,page}:OrganisationPageProps) {
export default function OrganisationPage({organisation,slug,page,ror}:OrganisationPageProps) {
const [pageState, setPageState] = useState<OrganisationMenuProps>()
const {loading, isMaintainer} = useOrganisationMaintainer({
organisation: organisation.id
Expand Down Expand Up @@ -83,9 +85,10 @@ export default function OrganisationPage({organisation,slug,page}:OrganisationPa
organisation={organisation}
isMaintainer={isMaintainer}
/>
<OrganisationLogo
<OrganisationMetadata
organisation={organisation}
isMaintainer={isMaintainer}
{...organisation}
meta={ror}
/>
</div>
<div className="flex flex-col min-h-[55rem]">
Expand Down Expand Up @@ -114,10 +117,12 @@ export async function getServerSideProps(context:GetServerSidePropsContext) {
notFound: true,
}
}

// get organisation metadata from ROR
const ror = await getOrganisationMetadata(organisation.ror_id ?? null)
return {
// passed to the page component as props
props: {
ror,
organisation,
slug: params?.slug,
page: query?.page ?? '',
Expand Down
2 changes: 1 addition & 1 deletion frontend/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ module.exports = {
'base-200':`var(--rsd-base-200,${colors['base-200']})`,
'base-300':`var(--rsd-base-300,${colors['base-300']})`,
'base-content':`var(--rsd-base-content,${colors['base-content']})`,
'base-content-disabled':`var(--rsd-base-content,${colors['base-content-disabled']})`,
'base-content-disabled':`var(--rsd-base-content-disabled,${colors['base-content-disabled']})`,
primary:`var(--rsd-primary,${colors.primary})`,
'primary-content':`var(--rsd-primary-content,${colors['primary-content']})`,
secondary:`var(--rsd-secondary,${colors.secondary})`,
Expand Down
21 changes: 21 additions & 0 deletions frontend/utils/getROR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,27 @@ function buildAutocompleteOptions(rorItems: RORItem[]): AutocompleteOption<Searc
return options
}


export async function getOrganisationMetadata(ror_id: string|null) {
try {
// check availability
if (typeof ror_id === 'undefined') return null
if (ror_id === null && ror_id === '') return null
// build url
const url = `https://api.ror.org/organizations/${ror_id}`
const resp = await fetch(url)
if (resp.status === 200) {
const json: RORItem = await resp.json()
return json
}
return null
} catch (e: any) {
logger(`getOrganisationMetadata failed. ${e.message}`)
return null
}
}


export type RORItem = typeof rorItem

// example of ROR item response
Expand Down

0 comments on commit 6a25f52

Please sign in to comment.