Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/components/WorkMetadata/WorkMetadata.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@
.id {
color: #3498db !important;
}

.divider {
border-bottom: 1px solid rgb(205, 210, 213);
margin-top: 1.5rem;
}
32 changes: 25 additions & 7 deletions src/components/WorkMetadata/WorkMetadata.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import { License } from 'src/components/License/License'
import MetricsCounter from 'src/components/MetricsCounter/MetricsCounter'
import styles from './WorkMetadata.module.scss'

import Claim from '../Claim/Claim'
import { session } from 'src/utils/session';

type Props = {
metadata: Work
linkToExternal?: boolean
Expand Down Expand Up @@ -135,7 +138,9 @@ export default function WorkMetadata({
)
}

const user = session()
const claim = metadata.claims ? metadata.claims[0] : null
const shouldDisplayOrcidButton = user && !hideMetadataInTable && metadata.doi && metadata.registrationAgency.id === 'datacite'

Comment on lines +141 to 144
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Guard session() for SSR and consider sync decode to avoid always-null user.

Calling session() at render can break on the server (Cookies/window not available) and, as implemented, verify() with a callback likely returns before setting user, yielding null. This can hide the button unintentionally.

Minimal guard in this component:

-  const user = session()
+  const user = typeof window !== 'undefined' ? session() : null
-  const shouldDisplayOrcidButton = user && !hideMetadataInTable && metadata.doi && metadata.registrationAgency.id === 'datacite'
+  const shouldDisplayOrcidButton =
+    !!user &&
+    !hideMetadataInTable &&
+    !!metadata.doi &&
+    metadata.registrationAgency?.id === 'datacite'

If session() is using asynchronous verification, please switch to a synchronous decode/verify (no callback) or a lightweight decode (e.g., jwt-decode) on the client. I can open a follow-up PR to adjust session() accordingly.

Run this script to confirm the async verify pattern in session.ts:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "session() implementation:"
rg -n -A5 -B8 $'export\\s+const\\s+session\\s*=\\s*\\(' src/utils/session.ts

echo
echo "Check for async JsonWebToken.verify callback usage:"
rg -n -C2 'JsonWebToken\\.verify\\s*\\(.*\\,\\s*.*\\,\\s*\\{[^}]*\\}\\s*,\\s*[^)]*\\)' src/utils/session.ts || true

Length of output: 970


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Displaying full session() implementation in src/utils/session.ts:"
sed -n '1,200p' src/utils/session.ts

Length of output: 970


Ensure session() is synchronous and guard against SSR to correctly display the ORCID button

The current session() implementation uses JsonWebToken.verify with a callback, so it always returns null (the callback runs after return). Additionally, calling session() during SSR may throw if window/cookies aren’t available.

• src/utils/session.ts

  • Replace the async callback pattern with a synchronous verify or lightweight decode.
  • Example refactor:
export const session = (): User => {
  if (!JWT_KEY) return null
  const sessionCookie = Cookies.getJSON('_datacite')
  const token = sessionCookie?.authenticated?.access_token
  if (!token) return null

- let user: any = null
- function setUser(error: any, payload: any) {
-   if (error) {
-     console.log('JWT verification error: ' + error.message)
-     return
-   }
-
-   user = payload
- }
-
- JsonWebToken.verify(token, JWT_KEY, { algorithms: ['RS256'] }, setUser)
-
- return user as User
+ try {
+   return JsonWebToken.verify(token, JWT_KEY, { algorithms: ['RS256'] }) as User
+ } catch (err) {
+   console.error('JWT verification error:', err)
+   return null
+ }
}

• src/components/WorkMetadata/WorkMetadata.tsx

  • Guard client‐only calls and tighten null checks:
- const user = session()
+ const user = typeof window !== 'undefined' ? session() : null

- const shouldDisplayOrcidButton = user && !hideMetadataInTable && metadata.doi && metadata.registrationAgency.id === 'datacite'
+ const shouldDisplayOrcidButton =
+   Boolean(user) &&
+   !hideMetadataInTable &&
+   Boolean(metadata.doi) &&
+   metadata.registrationAgency?.id === 'datacite'

Let me know if you’d like assistance wiring up a React hook or using jwt-decode for a lighter client‐side implementation.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const user = session()
const claim = metadata.claims ? metadata.claims[0] : null
const shouldDisplayOrcidButton = user && !hideMetadataInTable && metadata.doi && metadata.registrationAgency.id === 'datacite'
const user = typeof window !== 'undefined' ? session() : null
const claim = metadata.claims ? metadata.claims[0] : null
const shouldDisplayOrcidButton =
Boolean(user) &&
!hideMetadataInTable &&
Boolean(metadata.doi) &&
metadata.registrationAgency?.id === 'datacite'
🤖 Prompt for AI Agents
In src/components/WorkMetadata/WorkMetadata.tsx around lines 141 to 144, the
call to session() is currently returning null because the session helper uses an
async callback verify and is also unsafe during SSR; replace the session
implementation in src/utils/session.ts with a synchronous token decode/verify
(for example use jwt-decode or a synchronous verify call) so session() returns
the user immediately, and in this file guard the client-only call by checking
typeof window !== 'undefined' before invoking session(), and tighten the
ORCID-button condition to ensure metadata.registrationAgency exists and has id
=== 'datacite' and metadata.doi is present and user is non-null so the
shouldDisplayOrcidButton is computed safely on the client.

const container = () => {
if (metadata.container
Expand Down Expand Up @@ -191,7 +196,7 @@ export default function WorkMetadata({
if (!metadata.descriptions || !metadata.descriptions[0]) return ''

const descriptionHtml = truncate(metadata.descriptions[0].description, {
length: 2500,
length: 350,
separator: '… '
})

Expand Down Expand Up @@ -287,10 +292,23 @@ export default function WorkMetadata({
return (
<Row>
<Col className="card-body">
{!hideTitle && title()}
{includeMetricsDisplay && <MetricsDisplay counts={{ citations: metadata.citationCount, views: metadata.viewCount, downloads: metadata.downloadCount }} />}
{!hideMetadataInTable && creators()}
{metadataTag()}
{!hideTitle && (
<div className='row'>
<div
className={`col-${shouldDisplayOrcidButton ? '9' : '12'}`}
>
{title()}
{includeMetricsDisplay && <MetricsDisplay counts={{ citations: metadata.citationCount, views: metadata.viewCount, downloads: metadata.downloadCount }} />}
{!hideMetadataInTable && creators()}
{metadataTag()}
</div>
{shouldDisplayOrcidButton && (
<div className="col-3" style={{ fontSize: '1rem'}}>
<Claim doi_id={metadata.doi} />
</div>
)}
</div>
)}
{!hideMetadataInTable && <>{description()}
{metadata.identifiers && metadata.identifiers.length > 0 && (
<Row>
Expand All @@ -311,9 +329,9 @@ export default function WorkMetadata({
{!hideMetadataInTable && <License rights={metadata.rights} />}
{!hideMetadataInTable && <MetricsCounter metadata={metadata} />}
{tags()}
{footer()}
{!hideMetadataInTable && <div className={styles.divider}/>}
</Col>

{footer()}
</Row>
)
}
Loading