issue-166-open-timestamps #220
@ -4,6 +4,7 @@ import {
|
|||||||
fromUnixTimestamp,
|
fromUnixTimestamp,
|
||||||
hexToNpub,
|
hexToNpub,
|
||||||
npubToHex,
|
npubToHex,
|
||||||
|
SigitStatus,
|
||||||
SignStatus
|
SignStatus
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
import { useSigitMeta } from '../../hooks/useSigitMeta'
|
import { useSigitMeta } from '../../hooks/useSigitMeta'
|
||||||
@ -15,6 +16,8 @@ import {
|
|||||||
faCalendar,
|
faCalendar,
|
||||||
faCalendarCheck,
|
faCalendarCheck,
|
||||||
faCalendarPlus,
|
faCalendarPlus,
|
||||||
|
faCheck,
|
||||||
|
faClock,
|
||||||
faEye,
|
faEye,
|
||||||
faFile,
|
faFile,
|
||||||
faFileCircleExclamation
|
faFileCircleExclamation
|
||||||
@ -22,7 +25,7 @@ import {
|
|||||||
import { getExtensionIconLabel } from '../getExtensionIconLabel'
|
import { getExtensionIconLabel } from '../getExtensionIconLabel'
|
||||||
import { useAppSelector } from '../../hooks/store'
|
import { useAppSelector } from '../../hooks/store'
|
||||||
import { DisplaySigner } from '../DisplaySigner'
|
import { DisplaySigner } from '../DisplaySigner'
|
||||||
import { Meta } from '../../types'
|
import { Meta, OpenTimestamp } from '../../types'
|
||||||
import { extractFileExtensions } from '../../utils/file'
|
import { extractFileExtensions } from '../../utils/file'
|
||||||
import { UserAvatar } from '../UserAvatar'
|
import { UserAvatar } from '../UserAvatar'
|
||||||
|
|
||||||
@ -42,7 +45,9 @@ export const UsersDetails = ({ meta }: UsersDetailsProps) => {
|
|||||||
completedAt,
|
completedAt,
|
||||||
parsedSignatureEvents,
|
parsedSignatureEvents,
|
||||||
signedStatus,
|
signedStatus,
|
||||||
isValid
|
isValid,
|
||||||
|
id,
|
||||||
|
timestamps
|
||||||
} = useSigitMeta(meta)
|
} = useSigitMeta(meta)
|
||||||
const { usersPubkey } = useAppSelector((state) => state.auth)
|
const { usersPubkey } = useAppSelector((state) => state.auth)
|
||||||
const userCanSign =
|
const userCanSign =
|
||||||
@ -51,6 +56,50 @@ export const UsersDetails = ({ meta }: UsersDetailsProps) => {
|
|||||||
|
|
||||||
const { extensions, isSame } = extractFileExtensions(Object.keys(fileHashes))
|
const { extensions, isSame } = extractFileExtensions(Object.keys(fileHashes))
|
||||||
|
|
||||||
|
const isTimestampVerified = (
|
||||||
|
timestamps: OpenTimestamp[],
|
||||||
|
nostrId: string
|
||||||
|
): boolean => {
|
||||||
|
const matched = timestamps.find((t) => t.nostrId === nostrId)
|
||||||
|
return !!(matched && matched.verification)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getOpenTimestampsInfo = (
|
||||||
|
timestamps: OpenTimestamp[],
|
||||||
|
nostrId: string
|
||||||
|
) => {
|
||||||
|
if (isTimestampVerified(timestamps, nostrId)) {
|
||||||
|
return <FontAwesomeIcon icon={faCheck} />
|
||||||
eugene marked this conversation as resolved
Outdated
|
|||||||
|
} else {
|
||||||
|
return <FontAwesomeIcon icon={faClock} />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCompletedOpenTimestampsInfo = (timestamp: OpenTimestamp) => {
|
||||||
|
if (timestamp.verification) {
|
||||||
|
return <FontAwesomeIcon icon={faCheck} />
|
||||||
|
} else {
|
||||||
|
return <FontAwesomeIcon icon={faClock} />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTimestampTooltipTitle = (label: string, isVerified: boolean) => {
|
||||||
|
return `${label} / Open Timestamp ${isVerified ? 'Verified' : 'Pending'}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const isUserSignatureTimestampVerified = () => {
|
||||||
|
if (
|
||||||
|
userCanSign &&
|
||||||
|
hexToNpub(usersPubkey) in parsedSignatureEvents &&
|
||||||
|
timestamps &&
|
||||||
|
timestamps.length > 0
|
||||||
|
) {
|
||||||
|
const nostrId = parsedSignatureEvents[hexToNpub(usersPubkey)].id
|
||||||
|
return isTimestampVerified(timestamps, nostrId)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return submittedBy ? (
|
return submittedBy ? (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.section}>
|
<div className={styles.section}>
|
||||||
@ -115,19 +164,36 @@ export const UsersDetails = ({ meta }: UsersDetailsProps) => {
|
|||||||
<p>Details</p>
|
<p>Details</p>
|
||||||
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={'Publication date'}
|
title={getTimestampTooltipTitle(
|
||||||
|
'Publication date',
|
||||||
|
!!(timestamps && id && isTimestampVerified(timestamps, id))
|
||||||
|
)}
|
||||||
placement="top"
|
placement="top"
|
||||||
arrow
|
arrow
|
||||||
disableInteractive
|
disableInteractive
|
||||||
>
|
>
|
||||||
<span className={styles.detailsItem}>
|
<span className={styles.detailsItem}>
|
||||||
<FontAwesomeIcon icon={faCalendarPlus} />{' '}
|
<FontAwesomeIcon icon={faCalendarPlus} />{' '}
|
||||||
{createdAt ? formatTimestamp(createdAt) : <>—</>}
|
{createdAt ? formatTimestamp(createdAt) : <>—</>}{' '}
|
||||||
|
{timestamps && timestamps.length > 0 && id && (
|
||||||
|
<span className={styles.ticket}>
|
||||||
|
{getOpenTimestampsInfo(timestamps, id)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={'Completion date'}
|
title={getTimestampTooltipTitle(
|
||||||
|
'Completion date',
|
||||||
|
!!(
|
||||||
|
signedStatus === SigitStatus.Complete &&
|
||||||
|
completedAt &&
|
||||||
|
timestamps &&
|
||||||
|
timestamps.length > 0 &&
|
||||||
|
timestamps[timestamps.length - 1].verification
|
||||||
|
)
|
||||||
|
)}
|
||||||
placement="top"
|
placement="top"
|
||||||
arrow
|
arrow
|
||||||
disableInteractive
|
disableInteractive
|
||||||
@ -135,13 +201,26 @@ export const UsersDetails = ({ meta }: UsersDetailsProps) => {
|
|||||||
<span className={styles.detailsItem}>
|
<span className={styles.detailsItem}>
|
||||||
<FontAwesomeIcon icon={faCalendarCheck} />{' '}
|
<FontAwesomeIcon icon={faCalendarCheck} />{' '}
|
||||||
{completedAt ? formatTimestamp(completedAt) : <>—</>}
|
{completedAt ? formatTimestamp(completedAt) : <>—</>}
|
||||||
|
{signedStatus === SigitStatus.Complete &&
|
||||||
|
completedAt &&
|
||||||
|
timestamps &&
|
||||||
|
timestamps.length > 0 && (
|
||||||
|
<span className={styles.ticket}>
|
||||||
|
{getCompletedOpenTimestampsInfo(
|
||||||
|
timestamps[timestamps.length - 1]
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
{/* User signed date */}
|
{/* User signed date */}
|
||||||
{userCanSign ? (
|
{userCanSign ? (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={'Your signature date'}
|
title={getTimestampTooltipTitle(
|
||||||
|
'Your signature date',
|
||||||
|
isUserSignatureTimestampVerified()
|
||||||
|
)}
|
||||||
placement="top"
|
placement="top"
|
||||||
arrow
|
arrow
|
||||||
disableInteractive
|
disableInteractive
|
||||||
@ -161,6 +240,16 @@ export const UsersDetails = ({ meta }: UsersDetailsProps) => {
|
|||||||
) : (
|
) : (
|
||||||
<>—</>
|
<>—</>
|
||||||
)}
|
)}
|
||||||
|
{hexToNpub(usersPubkey) in parsedSignatureEvents &&
|
||||||
|
timestamps &&
|
||||||
|
timestamps.length > 0 && (
|
||||||
|
<span className={styles.ticket}>
|
||||||
|
{getOpenTimestampsInfo(
|
||||||
|
timestamps,
|
||||||
|
parsedSignatureEvents[hexToNpub(usersPubkey)].id
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -31,8 +31,6 @@
|
|||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
justify-content: start;
|
|
||||||
|
|
||||||
> :first-child {
|
> :first-child {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
@ -44,3 +42,7 @@
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ticket {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
eugene marked this conversation as resolved
enes
commented
Tiny styling improvement, 5px padding to match the first icon. Tiny styling improvement, 5px padding to match the first icon.
|
|||||||
|
@ -294,7 +294,9 @@ export const VerifyPage = () => {
|
|||||||
return timestamp
|
return timestamp
|
||||||
})
|
})
|
||||||
|
|
||||||
if (upgradedUserTimestamps.length > 0) {
|
console.log('upgraded timestamps: ', upgradedTimestamps)
|
||||||
|
|
||||||
|
if (upgradedUserTimestamps.length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,6 +325,7 @@ export const VerifyPage = () => {
|
|||||||
updatedMeta.modifiedAt = unixNow()
|
updatedMeta.modifiedAt = unixNow()
|
||||||
|
|
||||||
const updatedEvent = await updateUsersAppData(updatedMeta)
|
const updatedEvent = await updateUsersAppData(updatedMeta)
|
||||||
|
console.log('updated event: ', updatedEvent)
|
||||||
if (!updatedEvent) return
|
if (!updatedEvent) return
|
||||||
|
|
||||||
const userSet = new Set<`npub1${string}`>()
|
const userSet = new Set<`npub1${string}`>()
|
||||||
|
Loading…
Reference in New Issue
Block a user
Can we make add the
className={styles.ticket}>
to the icon directly here instead of wrapping the SVG in the code below?