import React, { useCallback, useEffect, useState } from 'react';
import { NavLink, useParams } from 'react-router-dom';
import Loader from '../common/components/Loader';
import { IRouteParams } from '../common/interfaces/IRouteParams';
import Repository from '../common/repository/repository';
import { AssetType, IAsset } from './interfaces/IAsset';
import styled from 'styled-components';
import config from '../config.json';
import Title from '../common/components/LayoutComponents/Title';
// import { Button, Col, Input, Row, UncontrolledAlert } from 'reactstrap';
import { Button, Col, Form, FormGroup, Input, Label, Row, UncontrolledAlert } from 'reactstrap';
import Asset from '../composition_riv/components/Asset';
import { IApiPostResponse } from '../common/interfaces/IApiPostResponse';
import { formatDateString } from '../common/utils/Date';
import AppRoutes from '../AppRoutes';
import { useTranslations } from '../i18n/useTranslations';
import * as Constants from "../common/constants/library-constants";
import * as Global_Constants from "../common/constants/shared-constants";
import * as Dam_Constants from "../digital_assets_management/constants/dam-constants";
const AssetContainer = styled.div`
overflow-y: auto;
height:100%;
`;
const AssetDiv = styled.div`
display: flex;
flex-direction: column;
`;
const AssetIllustration = styled.div`
width: 100%;
max-height: 270px;
height: 270px;
display: flex;
justify-content: center;
.sdc-asset {
&.sdc-playlist {
height: 100%;
width: 100%;
}
}
`;
const AssetPropertyTitle = styled.div`
width: 100%;
font-weight: bold;
justify-content: top;
`;
const AssetTagsContainer = styled.div`
width: 100%;
display: flex;
width: 9rem;
`;
const TagContainer = styled.div.attrs({
'data-testid': 'new-asset-tag-container',
})`
display: flex;
align-items: center;
width: 9rem;
padding-bottom: 0.25rem;
`;
const ScrollableContainer = styled.div`
max-height: 270px;
overflow-y: auto;
width: 100%;
`;
const TagsList = styled.div.attrs({
className: 'col-sm-9',
})`
display: flex;
flex-wrap: wrap;
`;
const TagButton = styled.i`
cursor: pointer;
padding: 0.25rem 0.5rem;
color: darkred;
`;
export const AssetDetails = () => {
const i18n = useTranslations()
const [changeNameErrorMessage, setChangeNameErrorMessage] = useState('');
const [tagsErrorMessage, setTagsErrorMessage] = useState('');
const [resultLoaded, setResultLoaded] = useState(false);
const [assetVersions, setAssetVersions] = useState([] as IAsset[]);
const [selectedAsset, setSelectedAsset] = useState(null as unknown as IAsset);
const [selectedAssetIndex, setSelectedAssetIndex] = useState(0);
const [selectedAssetRoute, setSelectedAssetRoute] = useState<
string | undefined
>('');
const [showEditNameForm, setShowEditNameForm] = useState(false);
const [newAssetName, setNewAssetName] = useState('');
const [newTag, setNewTag] = useState('');
const [sequencesForScene, setSequencesForScene] = useState<IAsset[]>([]);
const { id } = useParams<IRouteParams>();
const retrieveAssetVersions = useCallback(async () => {
setResultLoaded(false);
const assets = await Repository.getInstance().getAssetVersions(
parseInt(id)
);
setAssetVersions(assets);
if (
assets !== null &&
assets[selectedAssetIndex] !== undefined &&
assets[selectedAssetIndex] !== null
) {
setSelectedAsset(assets[selectedAssetIndex]);
setSelectedAssetRoute(assetToRoute(assets[selectedAssetIndex]));
} else {
setSelectedAsset(null as unknown as IAsset);
}
setResultLoaded(true);
}, [id, selectedAssetIndex]);
useEffect(() => {
retrieveAssetVersions();
}, [retrieveAssetVersions]);
useEffect(() => {
if (!selectedAsset) return;
if (selectedAsset.file_type !== AssetType.Scene) return;
const retrieveSequences = async () => {
const sequenceNames =
await Repository.getInstance().getSequencesUsingScene(
selectedAsset.name
);
setSequencesForScene(sequenceNames);
};
retrieveSequences();
}, [selectedAsset]);
function changeSelectedVersion(e: React.ChangeEvent<HTMLInputElement>) {
const selectedId = e.target.value;
const selectedIndex = assetVersions.findIndex((ast) => ast.id.toString() === selectedId);
setSelectedAssetIndex(selectedIndex);
}
function toggleEditNameForm() {
setShowEditNameForm(!showEditNameForm);
}
function changeNewAssetName(evt: React.ChangeEvent<HTMLInputElement>) {
setNewAssetName(evt.target.value);
}
function changeNewTag(evt: React.ChangeEvent<HTMLInputElement>) {
setNewTag(evt.target.value);
}
function validateNewNameForm() {
return newAssetName !== '' && newAssetName !== selectedAsset?.name;
}
async function sendNewName() {
setChangeNameErrorMessage('');
setResultLoaded(false);
const data = new FormData();
data.append('newName', newAssetName);
const apiResponse = new IApiPostResponse();
await Repository.getInstance().editAssetName(
selectedAsset?.id,
data,
apiResponse,
i18n(Global_Constants.GLOBAL, Dam_Constants.CHECK_NETWORK_STATUS)
);
if (apiResponse.errorMessage != null) {
setChangeNameErrorMessage(apiResponse.errorMessage);
}
await retrieveAssetVersions();
}
async function removeTag(tagId: number) {
setResultLoaded(false);
await Repository.getInstance().removeTagFromAsset(selectedAsset?.id, tagId);
await retrieveAssetVersions();
}
async function addTag(tagName: string) {
if (selectedAsset?.tags.findIndex((t) => t.name === tagName) !== -1) return;
setTagsErrorMessage('');
setResultLoaded(false);
const data = new FormData();
data.append('assetId', selectedAsset?.id.toString());
data.append('tagName', tagName);
const apiResponse = new IApiPostResponse();
await Repository.getInstance().addTagToAsset(data, apiResponse);
if (apiResponse.errorMessage != null) {
setTagsErrorMessage(apiResponse.errorMessage);
}
setNewTag('');
await retrieveAssetVersions();
}
const setAssetIsSubstitution = async (checked: boolean) => {
setResultLoaded(false);
if (checked)
await Repository.getInstance().setIsSubstitutionAsset(selectedAsset.id);
else
await Repository.getInstance().UnsetIsSubstitutionAsset(selectedAsset.id);
await retrieveAssetVersions();
};
const assetTypeToDescription = (assetType: AssetType) => {
const types = new Map([
[AssetType.Image, 'Image'],
[AssetType.Scene, 'Scene'],
[AssetType.Sound, 'Son'],
[AssetType.Video, 'Vidéo'],
[AssetType.Sequence, 'Séquence'],
[AssetType.Text, 'Texte'],
[AssetType.Font, 'Police'],
[AssetType.Style, 'Style'],
[AssetType.PredefMessage, 'Message'],
[AssetType.Programmation, 'Programmation'],
]);
return types.get(assetType);
};
const assetToRoute = (asset: IAsset) => {
const types = new Map([
[AssetType.Sequence, AppRoutes.sequence(asset.id.toString())],
[AssetType.Scene, AppRoutes.editor(asset.id.toString())],
[
AssetType.PredefMessage,
AppRoutes.predefinedMessage(asset.id.toString()),
],
[AssetType.Playlist, AppRoutes.audioPlaylist(asset.id.toString())],
[AssetType.Style, AppRoutes.style(asset.id.toString())],
[AssetType.Programmation, AppRoutes.programmation(asset.id.toString())],
]);
return types.get(asset.file_type);
};
return (
<AssetContainer>
{!resultLoaded && <Loader />}
<Title>{i18n(Global_Constants.LIBRARY, Constants.RESOURCE_DETAILS)}: {selectedAsset?.name}</Title>
<Form>
<AssetDiv>
<AssetIllustration>
{selectedAsset && <Asset asset={selectedAsset} />}
</AssetIllustration>
<FormGroup row >
<Label for="version" sm={3}><AssetPropertyTitle>Version</AssetPropertyTitle></Label>
<Col sm={3}>
<Input
type="select"
id="version"
value={selectedAsset?.id}
onChange={changeSelectedVersion}
disabled={!assetVersions || !assetVersions.length || assetVersions.length === 1}
>
{assetVersions?.map((asset, index) => (
<option key={`${asset.version}-${index}`} value={asset.id}>
{asset.version}
</option>
))}
</Input>
</Col>
</FormGroup>
<FormGroup row>
<Label for="assetName" sm={3}><AssetPropertyTitle>{i18n(Global_Constants.GLOBAL, Global_Constants.NAME)}</AssetPropertyTitle></Label>
<Col sm={3}>
<div className="d-flex align-items-center">
{selectedAsset?.name}
<i
className={`ms-1 fa fa-lg fa-pencil-square${showEditNameForm ? '' : '-o'}`}
style={{ cursor: 'pointer' }}
onClick={toggleEditNameForm}
/>
</div>
</Col>
</FormGroup>
{showEditNameForm && (
<FormGroup row>
<Label for="newAssetName" sm={3}><AssetPropertyTitle>{i18n(Global_Constants.LIBRARY, Constants.NEW_NAME)}</AssetPropertyTitle></Label>
<Col sm={3}>
<Input
type="text"
id="newAssetName"
value={newAssetName}
onChange={changeNewAssetName}
placeholder={selectedAsset.name}
/>
<Button
className="btn btn-danger mt-1"
disabled={!validateNewNameForm()}
onClick={sendNewName}
>
{i18n(Global_Constants.LIBRARY, Global_Constants.CHANGE)}
</Button>
</Col>
{changeNameErrorMessage && (
<UncontrolledAlert color="danger">
Error: {changeNameErrorMessage}
</UncontrolledAlert>
)}
</FormGroup>
)}
<FormGroup row>
<Label for="creationDate" sm={3}><AssetPropertyTitle>{i18n(Global_Constants.GLOBAL, Global_Constants.CREATION_DATE)}</AssetPropertyTitle></Label>
<Col sm={3}>
<Input type="text" id="creationDate" value={formatDateString(selectedAsset?.created_at)} readOnly />
</Col>
</FormGroup>
<FormGroup row>
<Label for="modificationDate" sm={3}><AssetPropertyTitle>{i18n(Global_Constants.GLOBAL, Global_Constants.LAST_MODIFICATION_DATE)}</AssetPropertyTitle></Label>
<Col sm={3}>
<Input type="text" id="modificationDate" value={formatDateString(selectedAsset?.updated_at)} readOnly />
</Col>
</FormGroup>
<FormGroup row>
<Label for="resourceType" sm={3}><AssetPropertyTitle>{i18n(Global_Constants.LIBRARY, Constants.RESOURCE_TYPE)}</AssetPropertyTitle></Label>
<Col sm={3}>
<Input type="text" id="resourceType" value={assetTypeToDescription(selectedAsset?.file_type)} readOnly />
</Col>
</FormGroup>
<FormGroup row>
<Label for="dimension" sm={3}><AssetPropertyTitle>{i18n(Global_Constants.LIBRARY, Constants.SIZE)}</AssetPropertyTitle></Label>
<Col sm={3}>
<Input type="text" id="dimension" value={String(selectedAsset?.dimension)} readOnly />
</Col>
</FormGroup>
{selectedAsset && (selectedAsset?.file_type === AssetType.Image || selectedAsset?.file_type === AssetType.Text || selectedAsset?.file_type === AssetType.Style) && (
<FormGroup row>
<Label for="substitute" sm={3}><AssetPropertyTitle>{i18n(Global_Constants.LIBRARY, Constants.SUBSTITUTE_MESSAGE)}</AssetPropertyTitle></Label>
<Col sm={3}>
<Input
id="isSubstitution"
type="checkbox"
className="form-check-input"
checked={selectedAsset?.isSubstitution ?? false}
onChange={(e) => setAssetIsSubstitution(e.target.checked)}
/>
</Col>
</FormGroup>
)}
<FormGroup row>
<Label for="keywords" sm={3}><AssetPropertyTitle>{i18n(Global_Constants.LIBRARY, Constants.KEYWORDS)}</AssetPropertyTitle></Label>
<Col sm={3}>
<AssetTagsContainer>
<TagsList>
{selectedAsset?.tags.map((tag, i) => (
<TagContainer key={`asset-tag-${selectedAsset.name}-${i}`}>
<Input type="text" value={tag.name} readOnly />
<TagButton className="fa fa-xs fa-close" onClick={() => removeTag(tag.id)} />
</TagContainer>
))}
<TagContainer>
<Input
type="text"
id="new-asset-tag"
value={newTag}
placeholder={i18n(Global_Constants.LIBRARY, Constants.KEYWORD)}
onChange={changeNewTag}
/>
<TagButton className={`fa fa-plus ${newTag === '' ? 'sdc-disabled' : ''}`} onClick={() => addTag(newTag)} />
</TagContainer>
</TagsList>
</AssetTagsContainer>
{tagsErrorMessage && (
<UncontrolledAlert color="danger">
Error: {tagsErrorMessage}
</UncontrolledAlert>
)}
</Col>
</FormGroup>
{selectedAsset?.file_type === AssetType.Scene && sequencesForScene.length > 0 && (
<FormGroup row>
<Label for="sequences" sm={3}><AssetPropertyTitle>Utilized in sequences</AssetPropertyTitle></Label>
<Col sm={3}>
{sequencesForScene.map((s) => (
<div key={`seq-for-scene-${s.name}`}>
<NavLink to={AppRoutes.assetDetails(s.id.toString())}>
{s.name}
</NavLink>
</div>
))}
</Col>
</FormGroup>
)}
{selectedAssetRoute && (
<div>
<NavLink className="btn btn-secondary" to={selectedAssetRoute}>
{i18n(Global_Constants.INFORMATION, Global_Constants.MODIFY_BUTTON)}
</NavLink>
</div>
)}
</AssetDiv>
</Form>
</AssetContainer>
);
};
export default AssetDetails;