Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copyright external uri revisions #439

Merged
merged 4 commits into from
Dec 17, 2024
Merged
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
150 changes: 69 additions & 81 deletions src/components/form/CustomCopyrightForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,58 +113,52 @@
<div>
<strong>Copyright Permissions Granted on Ownership:</strong>
<ul>
{clauses?.customUriEnabled ? (
<>
<li key="customUriEnabled">
Custom URI Enabled: {descriptions?.customUriEnabled[true]}
</li>
<li key="customUri">
Custom URI: {clauses?.customUri || 'No URI Set'}
</li>
</>
) : (
Object.entries(clauses).map(([key, value]) => {
if (key === 'exclusiveRights') {
const exclusiveLabel =
exclusiveRightsOptions.find((option) => option?.value === value)
?.label || 'None'
return <li key={key}>Exclusive Rights: {exclusiveLabel}</li>
} else if (key === 'customUri' || key === 'expirationDate') {
return null
} else if (key === 'expirationDateExists') {
return (
<>
<li key={key}>
{clauseLabels[key]}: {descriptions[key][value]}
</li>
<li key="expirationDate">
{clauseLabels.expirationDate}:{' '}
{clauses.expirationDateExists && clauses.expirationDate
? new Date(clauses.expirationDate).toLocaleDateString(
'en-US',
{
year: 'numeric',
month: 'long',
day: 'numeric',
}
)
: 'None'}
</li>
</>
)
} else if (key === 'addendum') {
return <li key={key}>Addendum: {value ? '✅ Yes' : '🚫 No'}</li>
} else {
const displayValue =
descriptions[key]?.[value] || 'Unknown Status'
return (
{Object.entries(clauses).map(([key, value]) => {
if (key === 'exclusiveRights') {
const exclusiveLabel =
exclusiveRightsOptions.find((option) => option?.value === value)
?.label || 'None'
return <li key={key}>Exclusive Rights: {exclusiveLabel}</li>
} else if (key === 'customUri' || key === 'expirationDate') {
return null
} else if (key === 'expirationDateExists') {
return (
<>
<li key={key}>
{clauseLabels[key]}: {displayValue}
{clauseLabels[key]}: {descriptions[key][value]}
</li>
)
}
})
)}
<li key="expirationDate">
{clauseLabels.expirationDate}:{' '}
{clauses.expirationDateExists && clauses.expirationDate
? new Date(clauses.expirationDate).toLocaleDateString(
'en-US',
{
year: 'numeric',
month: 'long',
day: 'numeric',
}
)
: 'None'}
</li>
</>
)
} else if (key === 'addendum') {
return <li key={key}>Addendum: {value ? '✅ Yes' : '🚫 No'}</li>
} else if (key === 'customUriEnabled') {
return value ? (
<li key={key}>
Custom URI Enabled: {descriptions?.customUriEnabled[true]}
</li>
) : null
} else {
const displayValue = descriptions[key]?.[value] || 'Unknown Status'
return (
<li key={key}>
{clauseLabels[key]}: {displayValue}
</li>
)
}
})}
</ul>
<br />
</div>
Expand Down Expand Up @@ -284,6 +278,20 @@
documentText += `\n\n${clauseNumber++}. Expiration Date:\nThis Agreement is effective until the date of ${readableDate} (relative to the time of mint of the Work), after which the rights granted herein will terminate unless expressly renewed or extended in writing by the Creator. Upon expiration, all rights (including exclusive rights) returns back to the Creator's ownership and control.`
}

if (clauses.customUriEnabled && clauses.customUri) {
documentText += `\n\n${clauseNumber++}. Custom URI Reference and Retroactive Application:
The Work is subject to additional terms, conditions, and declarations specified at: ${
clauses.customUri
}. These external terms are hereby incorporated by reference into this Agreement and shall be considered binding to the same extent as if they were fully set forth herein.

This URI may serve one or both of the following purposes:
a) External Reference: The URI may contain supplementary terms, conditions, restrictions, or declarations that apply to this Work. These additional terms shall be considered as an extension of this Agreement.

b) Retroactive Application: If the URI points to a previous work by the same Creator, and the Creator can conclusively demonstrate through cryptographic proof that they control both the wallet address associated with this Work and the wallet address associated with the referenced work ${minterInfo}, then all terms, rights, and restrictions specified in this Agreement shall apply retroactively to the referenced work. Such proof must be verifiable through blockchain records or other cryptographic means that establish an undeniable connection between the Creator's wallet addresses and both works.

The Creator bears the burden of proving ownership of both works through wallet address verification, transaction histories, or other blockchain-based evidence. In the absence of such proof, the retroactive application shall be considered void while the external reference shall remain in effect. Any conflicts between the terms specified in the URI and this Agreement shall be resolved in favor of the more restrictive terms, unless explicitly stated otherwise in either document.`
}

documentText += `\n\n${clauseNumber++}. Jurisdiction and Legal Authority:
This Agreement is subject to and shall be interpreted in accordance with the laws of the jurisdiction in which the Creator and Owner(s) are domiciled. The rights granted hereunder are subject to any applicable international, national, and local copyright and distribution laws.`

Expand All @@ -308,7 +316,7 @@
}

return documentText
}, [address, clauseNumber, clauses, minterName])

Check warning on line 319 in src/components/form/CustomCopyrightForm.jsx

View workflow job for this annotation

GitHub Actions / build (18)

React Hook useCallback has a missing dependency: 'watch'. Either include it or remove the dependency array

// logic for checkboxes
const handleChange = useCallback((value, name) => {
Expand All @@ -321,31 +329,15 @@
} else {
newValue = value
}

if (name === 'customUriEnabled') {
if (newValue) {
setClauses((prev) => ({
...prev,
reproduce: null,
broadcast: null,
publicDisplay: null,
createDerivativeWorks: null,
exclusiveRights: null,
retainCreatorRights: null,
requireAttribution: null,
rightsAreTransferable: null,
expirationDateExists: null,
expirationDate: '',
releasePublicDomain: null,
customUriEnabled: true,
}))
} else {
setClauses((prev) => ({
...prev,
customUriEnabled: false,
customUri: prev.customUri,
}))
}
setClauses((prev) => ({
...prev,
customUriEnabled: newValue === true, // Set to true or false
...(newValue === false && { customUri: '' }), // Clear URI when disabled
}))
}

// Handle 'Release to Public Domain' logic
else if (name === 'releasePublicDomain' && newValue === true) {
setClauses({
Expand Down Expand Up @@ -424,9 +416,7 @@
clauses.releasePublicDomain ||
clauses.requireAttribution

if (clauses.customUriEnabled) {
documentText = `Custom URI: ${clauses.customUri}`
} else if (!hasActiveRights) {
if (!hasActiveRights && !clauses.customUriEnabled) {
documentText =
'No Permissions Chosen (For Addendum or Expiration Date sections to show, choose at least one option in the checkboxes above.)'
} else {
Expand Down Expand Up @@ -527,9 +517,8 @@
checked={clauses[clauseName]}
onCheck={(checked) => handleChange(checked, clauseName)}
disabled={
clauses.customUriEnabled ||
(clauses.releasePublicDomain &&
clauseName !== 'releasePublicDomain')
clauses.releasePublicDomain &&
clauseName !== 'releasePublicDomain'
}
/>
<span
Expand Down Expand Up @@ -583,7 +572,6 @@
}
placeholder="Select Ownership Share Type"
isDisabled={
clauses.customUriEnabled ||
!Object.values(clauses).some((value) => value && value !== 'none')
}
styles={select_style}
Expand Down Expand Up @@ -663,7 +651,7 @@
role="button"
tabIndex={0}
className={styles.modalInfoIcon}
onClick={() => handleModalOpen(clauseLabels['customUriEnabled'])}
onClick={() => handleModalOpen('customUri')}
onKeyPress={(event) =>
handleKeyPress(event, clauseLabels['customUriEnabled'])
}
Expand Down
36 changes: 32 additions & 4 deletions src/components/form/copyrightmodaltext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,36 @@ export const copyrightModalText = {
<p>In professional contexts, expiration dates are typically set on a case-to-case basis (when an artist signs a "deal" with a label or company these details come into play), but if the Creator wants to create a blanket policy for their rights to be effective only during a limited time period, this option can be used to set a standard for all editions that apply to all Owners at once.</p>
`,
customUri: `
<p>This feature allows creators to set a custom URI/URL for additional resources or information related to the NFT.</p>
<p>The custom URI can link to a variety of content, such as detailed metadata, licensing information, or the creator's personal website.</p>
<p>Note that the reference to the URI itself may be permanent (a link to someone's website, for example), but the destination itself may be editable, so unless modularity is what is needed, treat HTTP-based Custom URIs. (Destination links could be edited, or disappear.)</p>
<p>Custom URIs can be made fully decentralized by using IPFS CIDs (hashes) or other decentralized storage systems, for full immutability.</p>`
<p>The Custom URI feature serves two important functions for creators:</p>

<p><strong>1. External Reference:</strong><br>
- Link to additional terms, restrictions, or declarations for the Work
- Provide supplementary documentation or metadata
- Reference creator's canonical information or portfolio</p>

<p><strong>2. Retroactive Application:</strong><br>
- Point to a previous work by the same creator
- Apply current license terms to the referenced work
- Must be verifiable through wallet address ownership</p>

<p><strong>Important Considerations:</strong></p>
<ul>
<li>For standard web links (http://, https://):
<ul>
<li>- The URI reference is permanent, but destination content may change</li>
<li>- Consider carefully if changeable content aligns with your intentions</li>
<li>- Best for dynamic information that may need updates</li>
</ul>
</li>
<li>For decentralized storage (ipfs://, etc.):
<ul>
<li>- Content is immutable and permanently stored</li>
<li>- Ideal for fixed terms or historical references</li>
<li>- Recommended for legal documents and permanent declarations</li>
</ul>
</li>
</ul>

<p><strong>Verification Requirements:</strong><br>
When using this feature for retroactive application, creators must be able to prove ownership of both the current and referenced works through their wallet addresses. This typically requires maintaining access to both wallet addresses and being able to sign transactions or messages that verify ownership.</p>`
};
8 changes: 3 additions & 5 deletions src/pages/objkt-display/tabs/Copyright.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export const Copyright = () => {
rightsAreTransferable: 'Rights are Transferable (Secondary Sales)',
releasePublicDomain: 'Release to Public Domain',
customUriEnabled: 'Custom URI Enabled',
customUri: 'Custom URI',
customUri:
'Custom URI (External Terms & Works Connected To This Agreement)',
}

const descriptions = {
Expand Down Expand Up @@ -136,9 +137,6 @@ export const Copyright = () => {
<ul>
{licenseData?.clauses &&
Object.entries(licenseData?.clauses).map(([key, value]) => {
if (isCustomUriOnly() && key !== 'customUri') {
return null // Do not render other clauses if customUriEnabled is true
}
const title = clauseLabels[key]
const displayValue = descriptions[key]
? descriptions[key][value]
Expand Down Expand Up @@ -213,7 +211,7 @@ export const Copyright = () => {
</Container>
</>
)}
{nft?.rights !== 'custom' && nft?.rights && (
{nft?.rights && (
<Container>
<h3>License Information</h3>
<p>{nft?.rights}</p>
Expand Down
Loading