diff --git a/src/pages/ownership.tsx b/src/pages/ownership.tsx
index daa6edb69..acc4d0eb4 100644
--- a/src/pages/ownership.tsx
+++ b/src/pages/ownership.tsx
@@ -5,8 +5,9 @@ import { GLOBAL_CONSTANTS } from '@src/config-global.ts';
import { OgMetaTags } from '@src/components/og-meta-tags.tsx';
import Header from '@src/layouts/dashboard/header.tsx';
import HeaderContent from '@src/layouts/dashboard/header-content.tsx';
-import { OwnershipView } from '@src/sections/ownership/index';
+import { OwnershipView } from '@src/sections/ownership';
import { useSelector } from 'react-redux';
+import {WithAuth} from "@src/components/should-login/withAuth.tsx"
// ----------------------------------------------------------------------
@@ -31,9 +32,9 @@ export default function FileManagerPage() {
{canViewSection(sessionData) ? (
<>
-
+
>
) : (
diff --git a/src/sections/marketing/types.ts b/src/sections/marketing/types.ts
index 3bf076e2b..980f51913 100644
--- a/src/sections/marketing/types.ts
+++ b/src/sections/marketing/types.ts
@@ -7,7 +7,7 @@ export interface CampaignType {
expiration: number;
}
-export interface CampaignTableRowType extends CampaignType {}
+export type CampaignTableRowType = CampaignType
export interface CampaignTableRowProps {
row: CampaignTableRowType;
@@ -15,8 +15,8 @@ export interface CampaignTableRowProps {
}
export interface CampaignModalContentProps {
+ onConfirm?: () => void;
onClose: () => void;
- onConfirm: () => void;
}
export interface CampaignConfiguredIndicatorStateProps {
diff --git a/src/sections/ownership/CONSTANTS.tsx b/src/sections/ownership/CONSTANTS.tsx
new file mode 100644
index 000000000..25fd4fdf9
--- /dev/null
+++ b/src/sections/ownership/CONSTANTS.tsx
@@ -0,0 +1,27 @@
+import { COLORS } from '@src/sections/finance/CONSTANTS.tsx';
+
+export const OWNERSHIP_TABLE_HEAD = [
+ { id: 'name', label: 'Publication', minWidth: 300 },
+ { id: 'limit', label: 'Policies', minWidth: 100},
+ { id: 'budget', label: 'Restrictions', minWidth: 100},
+ { id: 'status', label: 'Status', minWidth: 100 },
+];
+
+export const LBL_STATUS_COLORS = {
+ active: COLORS.success,
+ deactivated: COLORS.warning,
+};
+
+export const LBL_TYPES_TEXTS = [
+ {id: 1,name: "Subscription"},
+ {id: 2,name: "Rent"},
+ {id: 3,name: "Buy",}
+];
+
+export const LBL_REGIONS_TEXTS = [
+ {id: 1,name: "US"},
+ {id: 2,name: "EU"},
+ {id: 3,name: "ASIA"},
+ {id: 4,name: "LATAM"},
+ {id: 5,name: "AFRICA"},
+]
diff --git a/src/sections/ownership/components/ownership-create.tsx b/src/sections/ownership/components/ownership-create.tsx
new file mode 100644
index 000000000..6793b3130
--- /dev/null
+++ b/src/sections/ownership/components/ownership-create.tsx
@@ -0,0 +1,53 @@
+// MUI IMPORTS
+import Button from '@mui/material/Button';
+
+// LOCAL IMPORTS
+import Iconify from '@src/components/iconify';
+import OwnershipModal from '@src/components/modal';
+import { useBoolean } from '@src/hooks/use-boolean';
+import { FC } from 'react';
+import { CampaignCreateProps } from '@src/sections/marketing/types.ts';
+import {OwnershipModalContent} from "@src/sections/ownership/components/ownership-modal-content.tsx"
+
+// ----------------------------------------------------------------------
+
+const OwnershipCreate: FC = ({ onSuccess }) => {
+ const ownershipConfirmPublish = useBoolean();
+
+ const handleClose = () => {
+ ownershipConfirmPublish.onFalse?.();
+ };
+
+ const handleClick = () => {
+ ownershipConfirmPublish.onTrue?.();
+ };
+
+ const handleConfirm = () => {
+ onSuccess?.();
+ ownershipConfirmPublish.onFalse();
+ };
+
+ return (
+ <>
+ }
+ variant="contained"
+ sx={{
+ color: 'white',
+ background: '#8E33FF',
+ }}
+ >
+ Register
+
+ }
+ />
+ >
+ );
+};
+
+export {OwnershipCreate};
diff --git a/src/sections/ownership/components/ownership-modal-content.tsx b/src/sections/ownership/components/ownership-modal-content.tsx
new file mode 100644
index 000000000..1904072e3
--- /dev/null
+++ b/src/sections/ownership/components/ownership-modal-content.tsx
@@ -0,0 +1,138 @@
+import LoadingButton from "@mui/lab/LoadingButton";
+import NeonPaper from '@src/sections/publication/components/neon-paper-container.tsx';
+import { FC, useState } from 'react';
+import {
+ Button,
+ DialogActions,
+ Divider,
+
+ Box, Typography, TextField, Stack,
+} from '@mui/material'
+import {notifyError, notifyInfo, notifySuccess} from '@notifications/internal-notifications.ts'
+import { SUCCESS } from '@notifications/success.ts';
+import { CampaignModalContentProps } from '@src/sections/marketing/types.ts';
+import Iconify from "@src/components/iconify"
+import {INFO} from "@notifications/info.ts"
+import {ERRORS} from "@notifications/errors.ts"
+import {replacePrefix} from "@src/utils/wallet.ts"
+import {useRegisterAsset} from "@src/hooks/protocol/use-register-asset.ts"
+import {useSubmitAssetToLens} from "@src/hooks/use-submit-assets-to-lens.ts"
+import {useGetAssetOwner} from "@src/hooks/protocol/use-get-asset-owner.ts"
+// ----------------------------------------------------------------------
+
+const OwnershipModalContent: FC = ({ onClose, onConfirm }) => {
+ const [hashes, setHashes] = useState('');
+ const { registerAsset } = useRegisterAsset();
+ const { submitAssetToLens } = useSubmitAssetToLens();
+ const { fetchOwnerAddress } = useGetAssetOwner();
+ const [isProcessing, setIsProcessing] = useState(false);
+ const [progress, setProgress] = useState(0);
+ const hashesArray = hashes.split(',')
+ .map(h => h.trim())
+ .filter(Boolean);
+
+ const RainbowEffect = isProcessing ? NeonPaper : Box;
+
+ // Validate fields, calculate expiration in seconds, and call the create function from the hook
+ const handleRegister = async () => {
+ if (!hashes) return;
+
+ setProgress(1);
+ setIsProcessing(true);
+
+ try {
+ for (const [index, hash] of hashesArray.entries()) {
+ try {
+ // 1. Report progress
+ notifyInfo(INFO.REGISTER_OWNERSHIP_PROGRESS, {
+ index: index + 1,
+ total: hashesArray.length,
+ options: { autoHideDuration: 3000 }
+ }, '', { autoHideDuration: 3000 });
+ setProgress(index + 1);
+
+ const isTaken = await fetchOwnerAddress(hash);
+
+ if (isTaken) {
+ notifyError(ERRORS.ASSET_ALREADY_REGISTERED_ERROR);
+ continue;
+ }
+
+ if (!isTaken) {
+ // 2. Register ownership (if it fails, it does not continue)
+ await registerAsset(hash);
+ }
+
+ // 3. Upload to Lens only if registration was successful
+ await submitAssetToLens(replacePrefix(hash));
+ notifySuccess(SUCCESS.OWNERSHIP_REGISTERED_SUCCESSFULLY, { count: index + 1 });
+ } catch (error) {
+ notifyError(ERRORS.ASSET_OWNERSHIP_REGISTER_ERROR, { hash: `${index + 1}/${hashesArray.length}` });
+ continue; // Continue with the next hash
+ }
+ }
+ } catch (error) {
+ notifyError(ERRORS.ASSET_OWNERSHIP_REGISTER_ERROR);
+ } finally {
+ setIsProcessing(false);
+ onClose();
+ }
+ };
+
+ return (
+ <>
+
+
+
+
+ Enter the hash(es) of the content you want to register
+
+
+ You can enter multiple hashes separated by commas.
+
+
+ setHashes(e.target.value)}
+ placeholder="e.g., hash1,hash2,hash3"
+ disabled={isProcessing}
+ />
+
+
+
+
+
+
+
+ }
+ >
+ Confirm
+
+
+
+ >
+ );
+};
+
+export {OwnershipModalContent};
diff --git a/src/sections/ownership/components/ownership-settings-modal-content.tsx b/src/sections/ownership/components/ownership-settings-modal-content.tsx
new file mode 100644
index 000000000..41f56b4a3
--- /dev/null
+++ b/src/sections/ownership/components/ownership-settings-modal-content.tsx
@@ -0,0 +1,170 @@
+import { FC, useState, useMemo, useEffect } from 'react';
+import { fetchAssetSettings, upsertAssetSettings } from '@src/utils/supabase-actions';
+import Box from "@mui/material/Box";
+import Grid from '@mui/material/Grid';
+import Divider from '@mui/material/Divider';
+import Typography from '@mui/material/Typography';
+import InputLabel from '@mui/material/InputLabel';
+import ListItemText from '@mui/material/ListItemText';
+import Select from '@mui/material/Select';
+import Checkbox from '@mui/material/Checkbox';
+import TextField from "@mui/material/TextField"
+import LoadingButton from "@mui/lab/LoadingButton";
+import NeonPaper from "@src/sections/publication/components/neon-paper-container.tsx";
+import {Button, FormControl, DialogActions, LinearProgress, MenuItem} from '@mui/material'
+import {OwnershipSettingsModalContentProps} from "@src/sections/ownership/types.ts"
+import {LBL_REGIONS_TEXTS, LBL_TYPES_TEXTS} from "@src/sections/ownership/CONSTANTS.tsx"
+import {randomKey} from "@src/utils/uuidv4.ts"
+// ----------------------------------------------------------------------
+const OwnershipSettingsModalContent: FC = (props) => {
+ const { onClose, onConfirm, assetData, } = props;
+ const [loading, setLoading] = useState(false);
+ const [formValues, setFormValues] = useState({ type: '', region: [] });
+ const { name, id } = assetData;
+
+ const RainbowEffect = loading ? NeonPaper : Box;
+
+ useEffect(() => {
+ const loadAssetSettings = async () => {
+ setLoading(true);
+ const { data, error } = await fetchAssetSettings(String(id));
+ if (data) {
+ const parsedRegions = JSON.parse(data.region);
+ const uniqueRegions = [...new Set(parsedRegions)];
+ // @ts-expect-error NO error handling
+ setFormValues({ type: data.type, region: uniqueRegions });
+ } else if (error) {
+ console.error('Error fetching asset settings:', error);
+ }
+ setLoading(false);
+ };
+
+ loadAssetSettings();
+ }, [id]);
+
+ // Validate that each field has a value greater or equal to 1
+ const isFormValid = useMemo(() => {
+ // Verify that each field has a value greater or equal to 1
+ return formValues.type !== '' && formValues.region.length > 0;
+ }, [formValues]);
+
+ const handleOnConfirm = async () => {
+ if (!isFormValid) return;
+
+ setLoading(true);
+ try {
+ const { error } = await upsertAssetSettings({
+ asset_id: String(id),
+ name,
+ type: formValues.type,
+ region: JSON.stringify(formValues.region)
+ });
+ if (error) {
+ throw new Error(error);
+ }
+ onConfirm?.();
+ } catch (err) {
+ console.error('Error configuring asset settings:', err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const flattenArray = (arr) => {
+ return arr.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenArray(val)) : acc.concat(val), []);
+ };
+
+ const handleSelectChange = (event) => {
+ const { name, value } = event.target;
+ const flattenedValue = Array.isArray(value) ? flattenArray(value) : [value];
+ const uniqueValues = [...new Set(flattenedValue)];
+ setFormValues((prev) => ({
+ ...prev,
+ [name]: name === 'region' ? uniqueValues : value,
+ }));
+ };
+
+ return (
+ <>
+ {loading && }
+
+
+
+
+ Define several settings for the publication like access type and region availability.
+
+
+
+
+
+ {LBL_TYPES_TEXTS.map((option) => (
+
+ ))}
+
+
+
+
+ Choose the region where content is available
+
+
+
+ Region
+
+
+
+
+
+
+
+
+
+
+
+ Confirm
+
+
+
+ >
+ );
+};
+
+export {OwnershipSettingsModalContent};
diff --git a/src/sections/ownership/components/ownership-settings-modal.tsx b/src/sections/ownership/components/ownership-settings-modal.tsx
new file mode 100644
index 000000000..aa64ef55e
--- /dev/null
+++ b/src/sections/ownership/components/ownership-settings-modal.tsx
@@ -0,0 +1,36 @@
+import { FC } from "react";
+import SettingsModal from '@src/components/modal';
+import {OwnershipSettingsModalContent} from "./ownership-settings-modal-content.tsx";
+import {OwnershipSettingsModalProps} from "@src/sections/ownership/types.ts"
+
+// ----------------------------------------------------------------------
+
+const OwnershipSettingsModal: FC = (props) => {
+ const { open, onSuccess, onClose, assetData } = props;
+
+ const handleClose = () => {
+ onClose?.();
+ };
+
+ const handlSuccess = () => {
+ onSuccess?.();
+ handleClose();
+ };
+
+ return (
+
+ }
+ />
+ );
+};
+
+export {OwnershipSettingsModal};
diff --git a/src/sections/ownership/components/ownership-table-row.tsx b/src/sections/ownership/components/ownership-table-row.tsx
new file mode 100644
index 000000000..4a4938ebf
--- /dev/null
+++ b/src/sections/ownership/components/ownership-table-row.tsx
@@ -0,0 +1,183 @@
+// MUI IMPORTS
+import Typography from '@mui/material/Typography';
+import TableRow from '@mui/material/TableRow';
+import TableCell from '@mui/material/TableCell';
+import ListItemText from '@mui/material/ListItemText';
+import Grid from '@mui/material/Grid';
+import Switch from '@mui/material/Switch';
+import { IconButton, MenuItem } from '@mui/material';
+
+// LOCAL IMPORTS
+import Iconify from '@src/components/iconify';
+import TextMaxLine from "@src/components/text-max-line";
+import { OwnershipSettingsModal} from "@src/sections/ownership/components/ownership-settings-modal.tsx";
+import CustomPopover, { usePopover } from '@src/components/custom-popover';
+import { capitalizeFirstLetter } from '@src/utils/text-transform.ts';
+import { useBoolean } from '@src/hooks/use-boolean';
+import {LBL_STATUS_COLORS} from '@src/sections/ownership/CONSTANTS.tsx'
+import {OwnershipTableRowProps} from "@src/sections/ownership/types.ts"
+import Stack from "@mui/material/Stack"
+import Image from "@src/components/image"
+import { OwnershipTimelineModal } from './ownership-timeline-modal';
+// ----------------------------------------------------------------------
+const OwnershipTableRow = ({ row, selected }: Readonly) => {
+ const { name, image, id, description, status, restrictions, police } = row;
+ const popover = usePopover();
+ const settingsModal = useBoolean();
+ const timelineModal = useBoolean();
+ const onSettingRow = () => {
+ settingsModal.onTrue();
+ };
+
+ const onTimelineRow = () => {
+ timelineModal.onTrue();
+ }
+
+ const handlePauseToggle = async (checked: boolean) => {
+ try {
+ console.log('handlePauseToggle', checked);
+ popover.onClose();
+ } catch (error) {
+ console.error(error);
+ }
+ };
+
+ const getColorByKey = (colorObj: Record, key: string): string => {
+ return (key && colorObj[key as keyof typeof colorObj]) || '';
+ };
+
+ const renderPrimary = (
+ <>
+
+
+
+
+ {name}}
+ secondary={{description}}
+ primaryTypographyProps={{ typography: 'body2' }}
+ secondaryTypographyProps={{
+ component: 'span',
+ color: 'text.disabled',
+ }}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {capitalizeFirstLetter(status.name ?? '')}
+
+
+
+
+
+
+
+
+
+ {
+ popover.onClose();
+ }}
+ arrow="right-top"
+ sx={{ width: 160 }}
+ >
+
+
+
+
+
+ {}}
+ assetData={{
+ id: id,
+ name: name,
+ }}
+ />
+ {}}
+ assetData={{
+ name: name,
+ }}
+ />
+ >
+ );
+
+ return <>{renderPrimary}>;
+}
+
+export { OwnershipTableRow };
diff --git a/src/sections/ownership/components/ownership-table.tsx b/src/sections/ownership/components/ownership-table.tsx
new file mode 100644
index 000000000..f9faf4ad7
--- /dev/null
+++ b/src/sections/ownership/components/ownership-table.tsx
@@ -0,0 +1,104 @@
+// REACT IMPORTS
+import { FC } from 'react';
+
+// MUI IMPORTS
+import TableBody from '@mui/material/TableBody';
+import TableCell from "@mui/material/TableCell";
+import TableRow from "@mui/material/TableRow";
+import { Box, Table, TableContainer } from '@mui/material';
+
+// LOCAL IMPORTS
+import Scrollbar from '@src/components/scrollbar';
+import {
+ emptyRows,
+ TableEmptyRows,
+ TableHeadCustom,
+ TableNoData,
+ TablePaginationCustom,
+ useTable,
+} from '@src/components/table';
+import { LoadingScreen } from "@src/components/loading-screen";
+import { COLORS } from '@src/layouts/config-layout';
+import {OwnershipTableProps} from "@src/sections/ownership/types.ts"
+import {OWNERSHIP_TABLE_HEAD} from "@src/sections/ownership/CONSTANTS.tsx"
+import {OwnershipTableRow} from "@src/sections/ownership/components/ownership-table-row.tsx"
+
+// ----------------------------------------------------------------------
+
+const OwnershipTable: FC = (args) => {
+ const { assets, loading } = args;
+
+ const table = useTable({
+ defaultOrder: 'desc',
+ defaultOrderBy: 'createdAt',
+ });
+
+ const notFound = !assets.length && !loading;
+ const denseHeight = table.dense ? 52 : 72;
+
+ return (
+ <>
+
+
+
+
+
+
+ {loading ? (
+
+
+
+
+
+ ) : (
+ <>
+ {assets
+ .slice(
+ table.page * table.rowsPerPage,
+ table.page * table.rowsPerPage + table.rowsPerPage
+ )
+ .map((row) => (
+
+ ))}
+
+
+ >
+ )}
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default OwnershipTable;
diff --git a/src/sections/ownership/components/ownership-timeline-modal-content.tsx b/src/sections/ownership/components/ownership-timeline-modal-content.tsx
new file mode 100644
index 000000000..6c3ed16ce
--- /dev/null
+++ b/src/sections/ownership/components/ownership-timeline-modal-content.tsx
@@ -0,0 +1,90 @@
+import Grid from '@mui/material/Grid';
+import Divider from '@mui/material/Divider';
+import {FC, useEffect, useState} from 'react'
+import {Button, DialogActions, LinearProgress} from '@mui/material'
+import {
+ OwnershipSettingsModalContentProps,
+ OwnershipTimelineItemProps,
+} from "@src/sections/ownership/types.ts"
+import Timeline from '@mui/lab/Timeline';
+import {timelineItemClasses} from '@mui/lab/TimelineItem'
+
+import {OwnershipTimelineItem} from "@src/sections/ownership/components/ownership-timeline-modal-item.tsx"
+
+const list: OwnershipTimelineItemProps[] = [
+ {
+ id: '1',
+ title: '0x9d1f...4751DD listed for',
+ time: new Date(),
+ type: 'order1',
+ },
+ {
+ id: '2',
+ title: '0x9d1f...4751DD transferred to 0x9d1f...4751DD',
+ time: new Date(),
+ type: 'order2',
+ },
+ {
+ id: '3',
+ title: '0x9d1f...4751DD transferred to 0x212121....',
+ time: new Date(),
+ type: 'order2',
+ },
+ {
+ id: '4',
+ title: '0x9d1f...4751DD transferred to 0x9d1f...4751DD',
+ time: new Date(),
+ type: 'order2',
+ },
+ ]
+
+// ----------------------------------------------------------------------
+const OwnershipTimelineModalContent: FC = (props) => {
+ const { onClose } = props;
+ const [loading, setLoading] = useState(false);
+
+ useEffect(() => {
+ setLoading(true);
+
+ setTimeout(() => {
+ setLoading(false);
+ }, 1000);
+ }, [])
+
+ return (
+ <>
+
+
+
+
+ {loading && }
+
+
+
+ {list.map((item, index) => (
+
+ ))}
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export {OwnershipTimelineModalContent};
diff --git a/src/sections/ownership/components/ownership-timeline-modal-item.tsx b/src/sections/ownership/components/ownership-timeline-modal-item.tsx
new file mode 100644
index 000000000..dd4ef8e73
--- /dev/null
+++ b/src/sections/ownership/components/ownership-timeline-modal-item.tsx
@@ -0,0 +1,36 @@
+import {OwnershipTimelineItemsProps} from "@src/sections/ownership/types.ts"
+import TimelineItem from "@mui/lab/TimelineItem"
+import TimelineSeparator from "@mui/lab/TimelineSeparator"
+import TimelineDot from "@mui/lab/TimelineDot"
+import TimelineConnector from "@mui/lab/TimelineConnector"
+import TimelineContent from "@mui/lab/TimelineContent"
+import {Typography} from "@mui/material"
+import {fDateTime} from "@src/utils/format-time.ts"
+
+const OwnershipTimelineItem = ({ item, lastTimeline }: OwnershipTimelineItemsProps)=> {
+ const { type, title, time } = item;
+ return (
+
+
+
+ {lastTimeline ? null : }
+
+
+
+ {title}
+
+
+ {fDateTime(time)}
+
+
+
+ );
+}
+
+export {OwnershipTimelineItem};
diff --git a/src/sections/ownership/components/ownership-timeline-modal.tsx b/src/sections/ownership/components/ownership-timeline-modal.tsx
new file mode 100644
index 000000000..ea5a95565
--- /dev/null
+++ b/src/sections/ownership/components/ownership-timeline-modal.tsx
@@ -0,0 +1,36 @@
+import { FC } from "react";
+import SettingsModal from '@src/components/modal';
+import {OwnershipSettingsModalProps} from "@src/sections/ownership/types.ts"
+import {OwnershipTimelineModalContent} from "@src/sections/ownership/components/ownership-timeline-modal-content.tsx"
+
+// ----------------------------------------------------------------------
+
+const OwnershipTimelineModal: FC = (props) => {
+ const { open, onSuccess, onClose, assetData } = props;
+
+ const handleClose = () => {
+ onClose?.();
+ };
+
+ const handlSuccess = () => {
+ onSuccess?.();
+ handleClose();
+ };
+
+ return (
+
+ }
+ />
+ );
+};
+
+export {OwnershipTimelineModal};
diff --git a/src/sections/ownership/index.tsx b/src/sections/ownership/index.tsx
index df9002fdf..12d60a630 100644
--- a/src/sections/ownership/index.tsx
+++ b/src/sections/ownership/index.tsx
@@ -1 +1 @@
-export { default as OwnershipView } from '@src/sections/ownership/views/ownership-view.tsx';
+export { OwnershipView } from '@src/sections/ownership/views/ownership-view.tsx';
diff --git a/src/sections/ownership/types.ts b/src/sections/ownership/types.ts
new file mode 100644
index 000000000..03df9fac8
--- /dev/null
+++ b/src/sections/ownership/types.ts
@@ -0,0 +1,65 @@
+export interface OwnershipTableProps {
+ assets: OwnershipAsset[];
+ loading: boolean;
+}
+
+export interface OwnershipCreateProps {
+ onSuccess?: () => void;
+}
+
+export interface OwnershipTableRowProps {
+ row: OwnershipAsset;
+ selected: boolean;
+}
+
+export interface AssetPolicy {
+ name: string;
+}
+
+export interface AssetStatus {
+ name: string;
+}
+
+export interface AssetType {
+ name: string;
+}
+
+export interface OwnershipAsset {
+ id: number;
+ name: string;
+ image: string;
+ description: string;
+ police: AssetPolicy;
+ restrictions: boolean;
+ status: AssetStatus
+}
+
+export interface OwnershipSettingsModalProps {
+ open: boolean;
+ onClose?: () => void;
+ onSuccess?: () => void;
+ assetData: {
+ id: number;
+ name: string;
+ };
+}
+export interface OwnershipSettingsModalContentProps {
+ onClose?: () => void;
+ onConfirm?: () => void;
+ assetData: {
+ id: number
+ name: string;
+ };
+}
+
+export interface OwnershipTimelineItemProps {
+ id: string;
+ title: string;
+ time: Date;
+ type: string;
+}
+
+export interface OwnershipTimelineItemsProps {
+ item: OwnershipTimelineItemProps;
+ lastTimeline: boolean;
+}
diff --git a/src/sections/ownership/views/ownership-view.tsx b/src/sections/ownership/views/ownership-view.tsx
index 343c90090..b0f9e2801 100644
--- a/src/sections/ownership/views/ownership-view.tsx
+++ b/src/sections/ownership/views/ownership-view.tsx
@@ -1,7 +1,47 @@
-import Container from "@mui/material/Container";
-import Grid from "@mui/material/Unstable_Grid2";
-import Stack from "@mui/material/Stack";
-import OwnershipProcess from "@src/sections/ownership/components/ownership-process.tsx";
+import Grid from '@mui/material/Grid';
+import Container from '@mui/material/Container';
+import OwnershipTable from '@src/sections/ownership/components/ownership-table.tsx';
+import {OwnershipCreate} from "@src/sections/ownership/components/ownership-create.tsx"
+import { AssetPolicy, AssetStatus, OwnershipAsset } from '../types';
+import {CustomRandom} from "@src/utils/random.ts"
+
+const assetPolicies: AssetPolicy[] = [
+ { name: 'Subscription' },
+]
+
+const assetStatuses: AssetStatus[] = [
+ { name: 'Active' },
+ { name: 'Deactivated' },
+]
+
+const movies = [
+ {movie: 'Matrix Underground', image: 'https://i.blogs.es/8b8798/06-06-matrix/1366_2000.jpg'},
+ {movie: 'Titanic II', image: 'https://resizing.flixster.com/jt582j6FBD6irE_K_rGPlcSrii4=/206x305/v2/https://resizing.flixster.com/-XZAfHZM39UwaGJIFWKAE8fS0ak=/v3/t/assets/p8175397_p_v10_ab.jpg'},
+ {movie: 'Gladiator IV', image: 'https://media.sitioandino.com.ar/p/e9e4d7e62c53b7ba3b3cd6b85233a3c5/adjuntos/335/imagenes/000/737/0000737580/1200x630/smart/gladiadorpng.png'},
+ {movie: 'El Chavo and Spiderman', image: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR5A7xUMmL75NohLvMjgv9m0o6Ugqt_OQPk5w&s'},
+]
+
+const generateRandomAsset = (count: number): OwnershipAsset[] => {
+ const assets: OwnershipAsset[] = [];
+ for (let i = 0; i < count; i++) {
+ const randomPolicy = assetPolicies[Math.floor(CustomRandom.get() * assetPolicies.length)];
+ const randomStatus = assetStatuses[Math.floor(CustomRandom.get() * assetStatuses.length)];
+ const randomName = movies[Math.floor(CustomRandom.get() * movies.length)];
+
+ const asset: OwnershipAsset = {
+ id: i + 1,
+ name: randomName.movie,
+ image: randomName.image,
+ description: `Description for ${randomName.movie}`,
+ police: randomPolicy,
+ restrictions: CustomRandom.get() < 0.5,
+ status: randomStatus
+ };
+
+ assets.push(asset);
+ }
+ return assets;
+}
const OwnershipView = () => {
return (
@@ -12,21 +52,24 @@ const OwnershipView = () => {
maxWidth: '100% !important',
}}
>
-
-
-
-
-
-
+
+ {}} />
+
+
+
+
- )
-}
+ );
+};
-export default OwnershipView;
+export {OwnershipView}
diff --git a/src/utils/random.ts b/src/utils/random.ts
new file mode 100644
index 000000000..a4f10eee2
--- /dev/null
+++ b/src/utils/random.ts
@@ -0,0 +1,33 @@
+/**
+ * CustomRandom is an object implementing a linear congruential generator (LCG) for generating pseudo-random numbers.
+ * It uses specific LCG parameters to calculate random values and provides methods for retrieving these values.
+ *
+ * Properties:
+ * - seed: The initial seed used to produce random numbers. It is set to the current time in milliseconds.
+ * - a: Multiplier parameter used in the LCG formula.
+ * - c: Increment parameter used in the LCG formula.
+ * - m: Modulus parameter used in the LCG formula (set to 2^32).
+ *
+ * Methods:
+ * - next: Computes the next pseudo-random number in the sequence as per the LCG formula.
+ * Updates the seed value and returns a number between 0 and 1.
+ * - getRandomDecimal: Generates a pseudo-random decimal between 0 and 1, rounded down to one decimal place.
+ */
+export const CustomRandom = {
+ seed: new Date().getTime(),
+
+ // LCG parameters
+ a: 1664525,
+ c: 1013904223,
+ m: Math.pow(2, 32),
+
+ next() {
+ this.seed = (this.a * this.seed + this.c) % this.m;
+ return this.seed / this.m;
+ },
+
+ get() {
+ const randomValue = this.next();
+ return Math.floor(randomValue * 10) / 10;
+ }
+};
diff --git a/src/utils/supabase-actions.ts b/src/utils/supabase-actions.ts
index 44028d543..ad60bd1cb 100644
--- a/src/utils/supabase-actions.ts
+++ b/src/utils/supabase-actions.ts
@@ -218,3 +218,30 @@ export const checkIfEmailAlreadyInvited = async (
return { invited: false, error: err.message };
}
};
+
+
+export const fetchAssetSettings = async (asset_id: string) => {
+ try {
+ const { data, error } = await supabase
+ .from('ownership')
+ .select('type, region')
+ .eq('asset_id', asset_id)
+ .single();
+
+ return { data, error: error ? error.message : null };
+ } catch (err: any) {
+ return { data: null, error: err.message };
+ }
+};
+
+export const upsertAssetSettings = async (assetSettings: { asset_id: string, name: string, type: string, region: string }) => {
+ try {
+ const { data, error } = await supabase
+ .from('ownership')
+ .upsert(assetSettings, { onConflict: ['asset_id'] });
+
+ return { data, error: error ? error.message : null };
+ } catch (err: any) {
+ return { data: null, error: err.message };
+ }
+};