Skip to content

Commit

Permalink
Merge pull request #513 from WatchItDev/app/temporal/ownership
Browse files Browse the repository at this point in the history
feat: added ownership registration
  • Loading branch information
geolffreym authored Jan 30, 2025
2 parents da23610 + 5c83371 commit 2a52a1d
Show file tree
Hide file tree
Showing 30 changed files with 9,570 additions and 312 deletions.
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,
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

0 comments on commit 2a52a1d

Please sign in to comment.