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

feat: added ownership registration #513

Merged
merged 31 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c613371
feat: add free trial button with neon effect and loading state
cswni Jan 8, 2025
f7e7d3e
feat: added change wallet feature on deposit/withdraw modals
Jadapema Jan 8, 2025
7331548
refactor: replace LoadingButton with custom StyledBoxGradient
cswni Jan 8, 2025
e7a42d3
feat: make free trial as button
Jadapema Jan 8, 2025
aa4949a
feat(studio): implement Studio section with publishing process
cswni Jan 8, 2025
e3f89a3
feat(marketing): add marketing components and assets
cswni Jan 8, 2025
aa92b43
feat: update contracts
Jadapema Jan 9, 2025
7dbf47e
feat: added terms and licenses handling, update subscription campaign…
Jadapema Jan 9, 2025
8e5397b
Merge branch 'next' into app/marketing/studio
Jadapema Jan 27, 2025
562fb98
feat: added modals and cards
Jadapema Jan 28, 2025
29c9f7e
refactor: typo renamed to Paid
geolffreym Jan 28, 2025
8d7b4d7
feat: add ownership illustration SVG to assets
cswni Jan 28, 2025
2437206
refactor: rename StudioPublishModalProps to ModalProps
cswni Jan 28, 2025
bfbb36d
feat(marketing): add modular campaign content modal component
cswni Jan 28, 2025
a4b844e
refactor(ownership-process): simplify and reorganize component
cswni Jan 28, 2025
baedf9b
feat: add ProcessIllustrationCard component implementation
cswni Jan 28, 2025
27c3844
feat: add ProcessSectionCard component
cswni Jan 28, 2025
37ace93
refactor(studio-process): simplify UI components
cswni Jan 28, 2025
05c7fe1
Merge pull request #504 from WatchItDev/next
geolffreym Jan 29, 2025
0ac9a6f
feat: connect register ownership to the contract
Jadapema Jan 29, 2025
53aa4a0
Merge pull request #508 from WatchItDev/next
Jadapema Jan 29, 2025
a057b1d
feat: added ownership registration
Jadapema Jan 30, 2025
6489c2a
feat: added ownership registration
Jadapema Jan 30, 2025
c29773b
feat: added ownership registration
Jadapema Jan 30, 2025
55787f2
Merge branch 'next' into app/marketing/studio
Jadapema Jan 30, 2025
f541a6d
feat: added asset owner validation before register ownership, added s…
Jadapema Jan 30, 2025
137b7de
feat: added new AssetOwnership abi
Jadapema Jan 30, 2025
d932975
refactor: remove console logs
Jadapema Jan 30, 2025
2652eea
fix: sonarcloud
Jadapema Jan 30, 2025
f60e0a8
Merge branch 'main' into app/marketing/studio
Jadapema Jan 30, 2025
5c83371
refactor: clean unused code
Jadapema Jan 30, 2025
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
6,525 changes: 6,525 additions & 0 deletions src/assets/illustrations/marketing.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
544 changes: 544 additions & 0 deletions src/assets/illustrations/ownership.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1,300 changes: 1,300 additions & 0 deletions src/assets/illustrations/process.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions src/components/modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { FC } from 'react';

// MUI IMPORTS
import DialogTitle from '@mui/material/DialogTitle';
import Dialog, { DialogProps } from '@mui/material/Dialog';

interface ModalProps extends DialogProps {
onClose: VoidFunction;
title: string;
renderContent?: JSX.Element;
}

const Modal: FC<ModalProps> = ({ open, onClose, title, renderContent, ...dialogProps }) => {
return (
<Dialog open={open} fullWidth maxWidth="xs" onClose={onClose} {...dialogProps}>
<DialogTitle sx={{ pb: 1 }}>{title}</DialogTitle>
{renderContent}
</Dialog>
);
};

export default Modal;
35 changes: 35 additions & 0 deletions src/components/process-illustration-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Image from "@src/components/image";
import Stack from "@mui/material/Stack";
import {FC} from "react";

interface ProcessIllustrationCardProps {
illustration: string;
alt?: string;
}

const ProcessIllustrationCard: FC<ProcessIllustrationCardProps> = ({illustration, alt}) => {

return (
<Stack
flexGrow={1}
justifyContent="center"
sx={{
display: { xs: 'flex', md: 'flex' },
p: { xs: 1, md: 1 },
mb: { xs: 1, md: 0 },
mx: 'auto',
order: { xs: 1, md: 2 },
}}
>
<Image
sx={{
objectFit: 'contain'
}}
src={illustration}
alt={alt}
/>
</Stack>
)
}

export default ProcessIllustrationCard;
121 changes: 121 additions & 0 deletions src/components/process-section-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { FC } from 'react';
import { Stack, Typography} from '@mui/material';
import LoadingButton from '@mui/lab/LoadingButton';
import { alpha, useTheme } from '@mui/material/styles';
import { bgGradient } from '@src/theme/css';
import Iconify from '@src/components/iconify';
import { useResponsive } from '@src/hooks/use-responsive';
import ProcessIllustrationCard from '@src/components/process-illustration-card.tsx';

interface ProcessSectionCardProps {
title: string;
description: string;
buttonText: string;
illustration: string;
illustrationAlt: string;
onClick: () => void;
}

const ProcessSectionCard: FC<ProcessSectionCardProps> = ({
title,
description,
buttonText,
illustration,
illustrationAlt,
onClick
}) => {
const lgUp = useResponsive('up', 'lg');
const theme = useTheme();


return (
<Stack
sx={{
...bgGradient({
direction: '135deg',
}),
width: {
xs: 1,
md: '60%',
},
maxWidth: {
xs: '100%',
md: 'calc(50%)',
},
borderRadius: 2,
overflow: 'hidden',
position: 'relative',
}}
>
<Stack
flexDirection={{ xs: 'column', md: 'row' }}
sx={{
...bgGradient({
direction: '135deg',
startColor: alpha(theme.palette.primary.light, 0.2),
endColor: alpha(theme.palette.primary.main, 0.2),
}),
height: { md: 1 },
borderTopRightRadius: 2,
borderTopLeftRadius: 2,
position: 'relative',
color: 'primary.darker',
backgroundColor: 'common.white',
}}
>
<Stack
justifyContent="flex-start"
alignItems={{ xs: 'center', md: 'flex-start' }}
sx={{
width: '100%',
flexShrink: 0,
maxWidth: { xs: '100%', md: '50%' },
p: {
xs: theme.spacing(3, 3, 0, 3),
md: theme.spacing(3),
},
textAlign: { xs: 'center', md: 'left' },
order: { xs: 2, md: 1 },
}}
>
<Typography
variant="body1"
sx={{
display: { md: 'flex' },
maxWidth: 250,
mb: 1,
whiteSpace: 'pre-line',
}}
>
{description}
</Typography>
<Typography
variant="h3"
sx={{
display: 'flex',
alignItems: 'center',
mb: { xs: 1, xl: 2 },
}}
>
{title}
</Typography>
<LoadingButton
sx={{
mt: lgUp ? 1 : null,
mb: !lgUp ? 3 : null,
}}
color="primary"
variant="soft"
startIcon={<Iconify icon="material-symbols:campaign-outline-rounded" />}
onClick={onClick}
>
{buttonText}
</LoadingButton>
</Stack>
<ProcessIllustrationCard illustration={illustration} alt={illustrationAlt} />
</Stack>
</Stack>
);
};

export default ProcessSectionCard;
1 change: 0 additions & 1 deletion src/components/subscribe-to-unlock-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export const SubscribeToUnlockCard = ({
This content is exclusively for members. Become part of our growing community to access
behind-the-scenes content, exclusive posts, and much more!
</Typography>

<LoadingButton
variant="contained"
color="primary"
Expand Down
16 changes: 13 additions & 3 deletions src/components/video-player/video-player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
MediaPlayerInstance,
MediaProvider,
useMediaState,
isHLSProvider,
isHLSProvider, Track
} from '@vidstack/react';
import { DefaultVideoLayout, defaultLayoutIcons } from '@vidstack/react/player/layouts/default';
import Label from '../label';
Expand All @@ -17,18 +17,25 @@ import '@vidstack/react/player/styles/default/theme.css';
import '@vidstack/react/player/styles/default/layouts/audio.css';
// @ts-ignore
import '@vidstack/react/player/styles/default/layouts/video.css';
import useGetSubtitles from '@src/hooks/use-get-subtitles.ts';

export type VideoPlayerProps = {
src: string;
cid: string;
titleMovie: string;
onBack?: () => void;
showBack?: boolean;
};

export const VideoPlayer: FC<VideoPlayerProps> = ({ src, titleMovie, onBack, showBack }) => {
export const VideoPlayer: FC<VideoPlayerProps> = ({ src, cid, titleMovie, onBack, showBack }) => {
const mdUp = useResponsive('up', 'md');
const player = useRef<MediaPlayerInstance>(null);
const controlsVisible = useMediaState('controlsVisible', player);
const { tracks, getSubtitles } = useGetSubtitles();

useEffect(() => {
if (cid) getSubtitles(cid);
}, [cid, getSubtitles]);

useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
Expand Down Expand Up @@ -81,7 +88,7 @@ export const VideoPlayer: FC<VideoPlayerProps> = ({ src, titleMovie, onBack, sho
enableDateRangeMetadataCues: false,
enableMetadataCues: false,
enableID3MetadataCues: false,
enableWebVTT: false, // TODO change when subtitles needed
enableWebVTT: true,
Copy link
Member

Choose a reason for hiding this comment

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

What happen of the movie has not subs?

enableIMSC1: false, // TODO change when subtitles needed
enableCEA708Captions: false, // TODO change when subtitles needed

Expand Down Expand Up @@ -188,6 +195,9 @@ export const VideoPlayer: FC<VideoPlayerProps> = ({ src, titleMovie, onBack, sho
)}
<MediaProvider />
<DefaultVideoLayout icons={defaultLayoutIcons} />
{tracks.map((track) => (
<Track key={track.src} {...track} />
))}
</MediaPlayer>
);
};
Expand Down
2 changes: 2 additions & 0 deletions src/config-global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export const GLOBAL_CONSTANTS = {
process.env.VITE_RIGHT_POLICY_AUTHORIZER || import.meta.env.VITE_RIGHT_POLICY_AUTHORIZER || '',
ACCESS_MANAGER_ADDRESS:
process.env.VITE_ACCESS_MANAGER_ADDRESS || import.meta.env.VITE_ACCESS_MANAGER_ADDRESS || '',
ASSET_OWNERSHIP_ADDRESS:
process.env.VITE_ASSET_OWNERSHIP_ADDRESS || import.meta.env.VITE_ASSET_OWNERSHIP_ADDRESS || '',
SENTRY_AUTH_TOKEN:
process.env.VITE_SENTRY_AUTH_TOKEN || import.meta.env.VITE_SENTRY_AUTH_TOKEN || '',
SENTRY_DSN: process.env.VITE_SENTRY_DSN || import.meta.env.VITE_SENTRY_DSN || '',
Expand Down
1 change: 1 addition & 0 deletions src/config/abi/AssetOwnership.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/config/abi/LedgerVault.json

Large diffs are not rendered by default.

104 changes: 104 additions & 0 deletions src/hooks/use-get-asset-owner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// REACT IMPORTS
import { useState, useCallback } from 'react';

// VIEM IMPORTS
import { Address } from 'viem';
import { publicClient } from '@src/clients/viem/publicClient';

// LOCAL IMPORTS
import AssetOwnershipAbi from '@src/config/abi/AssetOwnership.json';
import { GLOBAL_CONSTANTS } from '@src/config-global.ts';

// ----------------------------------------------------------------------

/**
* Interface for handling errors within the hook.
*/
interface GetAssetOwnerError {
message: string;
code?: number;
[key: string]: any;
}

/**
* Interface defining the structure of the hook's return value.
*/
interface UseGetAssetOwnerHook {
ownerAddress?: Address;
loading: boolean;
error?: GetAssetOwnerError | null;
fetchOwnerAddress: (assetIdHex: string) => Promise<Address | undefined>;
}

/**
* Hook to retrieve the owner's address of a specific asset.
*
* @returns {UseGetAssetOwnerHook} An object containing the owner's address, loading state, error information, and a function to fetch the owner's address.
*/
export const useGetAssetOwner = (): UseGetAssetOwnerHook => {
// State variables
const [ownerAddress, setOwnerAddress] = useState<Address | undefined>(undefined);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<GetAssetOwnerError | null>(null);

/**
* Converts a hexadecimal asset ID to decimal.
*
* @param hexId - The asset ID in hexadecimal format.
* @returns The asset ID in decimal format as a string.
*/
const convertHexToDecimal = (hexId: string): string => {
// Remove '0x' prefix if present
const cleanHex = hexId.startsWith('0x') ? hexId.slice(2) : hexId;
return BigInt(`0x${cleanHex}`).toString(10);
};

/**
* Fetches the owner's address of the asset.
*
* @param assetIdHex - The asset ID in hexadecimal format.
* @returns {Promise<Address | undefined>} The owner's address if successful, otherwise undefined.
*/
const fetchOwnerAddress = useCallback(async (assetIdHex: string): Promise<Address | undefined> => {
if (!assetIdHex) {
setError({ message: 'Asset ID is missing.' });
return undefined;
}

setLoading(true);
setError(null);

try {
// Convert assetId from hexadecimal to decimal
const assetIdDecimal = convertHexToDecimal(assetIdHex);

// Call the 'ownerOf' function on the AssetOwnership contract
const owner: any = await publicClient.readContract({
address: GLOBAL_CONSTANTS.ASSET_OWNERSHIP_ADDRESS,
abi: AssetOwnershipAbi.abi,
functionName: 'ownerOf',
args: [assetIdDecimal],
});

setOwnerAddress(owner);
setError(null);
return owner;
} catch (err: any) {
console.error('USE GET ASSET OWNER ERROR:', err);
setOwnerAddress(undefined);
setError({
message: err?.message || 'An error occurred while retrieving the asset owner.',
});
return undefined;
} finally {
setLoading(false);
}
}, []);

return {
ownerAddress,
loading,
error,
fetchOwnerAddress,
};
};
Loading
Loading