diff --git a/src/components/container-form/attribute.tsx b/src/components/container-form/attribute.tsx
index 7f55143..85f9b48 100644
--- a/src/components/container-form/attribute.tsx
+++ b/src/components/container-form/attribute.tsx
@@ -69,6 +69,10 @@ const typeOptions = [
label: ,
value: TYPES.RichText,
},
+ {
+ label: ,
+ value: TYPES.Asset,
+ },
];
type Props = {
diff --git a/src/components/container-form/messages.ts b/src/components/container-form/messages.ts
index f1aaa7e..89f53a1 100644
--- a/src/components/container-form/messages.ts
+++ b/src/components/container-form/messages.ts
@@ -192,4 +192,9 @@ export default defineMessages({
description: 'Label for attributes rich text value',
defaultMessage: 'Rich Text',
},
+ assetLabel: {
+ id: 'Container.form.type.label.asset',
+ description: 'Asset type label',
+ defaultMessage: 'Asset',
+ },
});
diff --git a/src/components/custom-object-form/asset-input/asset-input.tsx b/src/components/custom-object-form/asset-input/asset-input.tsx
new file mode 100644
index 0000000..8d6aa78
--- /dev/null
+++ b/src/components/custom-object-form/asset-input/asset-input.tsx
@@ -0,0 +1,123 @@
+// src/components/attribute-input/asset-input.js
+
+import Spacings from '@commercetools-uikit/spacings';
+import TextInput from '@commercetools-uikit/text-input';
+import LocalizedTextInput from '@commercetools-uikit/localized-text-input';
+import { useApplicationContext } from '@commercetools-frontend/application-shell-connectors';
+import Text from '@commercetools-uikit/text';
+import { FC } from 'react';
+import SourceArrayInput from './source-array-input';
+import { Asset, LocalizedString, Source } from './types';
+
+type Props = {
+ name: string;
+ value?: any;
+ touched?: any;
+ errors?: any;
+ onChange: (...args: any[]) => void;
+ onBlur: (...args: any[]) => void;
+};
+
+const AssetInput: FC = ({
+ name,
+ value = {},
+ onChange,
+ touched,
+ errors,
+}) => {
+ const { dataLocale } = useApplicationContext((context) => ({
+ dataLocale: context.dataLocale ?? '',
+ }));
+
+ const triggerChange = (updatedValue: Partial) => {
+ onChange({ target: { name, value: updatedValue } });
+ };
+
+ const handleChange = (e: React.ChangeEvent) => {
+ const { name: fieldName, value: fieldValue } = e.target;
+ triggerChange({ ...value, [fieldName]: fieldValue });
+ };
+
+ const handleLocalizedChange = (
+ localizedValue: LocalizedString,
+ fieldName: string
+ ) => {
+ triggerChange({ ...value, [fieldName]: localizedValue });
+ };
+
+ const handleSourcesChange = (sources: Source[]) => {
+ triggerChange({ ...value, sources });
+ };
+
+ const handleTagsChange = (e: React.ChangeEvent) => {
+ const newTags = e.target.value
+ ? e.target.value.split(',').map((tag) => tag.trim())
+ : [];
+ triggerChange({ ...value, tags: newTags });
+ };
+
+ return (
+
+
+
+
+ Name:
+
+
+ }
+ value={value?.name || {}}
+ selectedLanguage={dataLocale}
+ onChange={(event) =>
+ handleLocalizedChange(
+ event.target.value as unknown as LocalizedString,
+ 'name'
+ )
+ }
+ hasError={!!(LocalizedTextInput.isTouched(touched) && errors)}
+ />
+ Description:
+ }
+ value={value?.description || {}}
+ selectedLanguage={dataLocale}
+ onChange={(event) =>
+ handleLocalizedChange(
+ event.target.value as unknown as LocalizedString,
+ 'description'
+ )
+ }
+ hasError={!!(LocalizedTextInput.isTouched(touched) && errors)}
+ />
+
+
+
+
+ Sources
+
+
+
+ );
+};
+
+export default AssetInput;
diff --git a/src/components/custom-object-form/asset-input/source-array-input.tsx b/src/components/custom-object-form/asset-input/source-array-input.tsx
new file mode 100644
index 0000000..a4ccac1
--- /dev/null
+++ b/src/components/custom-object-form/asset-input/source-array-input.tsx
@@ -0,0 +1,53 @@
+// src/components/attribute-input/source-array-input.tsx
+
+import React from 'react';
+import Spacings from '@commercetools-uikit/spacings';
+import SecondaryButton from '@commercetools-uikit/secondary-button';
+import Constraints from '@commercetools-uikit/constraints';
+import SourceInput from './source-input';
+import type { Source } from './types';
+
+type Props = {
+ value: Source[];
+ onChange: (value: Source[]) => void;
+};
+
+const SourceArrayInput: React.FC = ({ value = [], onChange }) => {
+ const handleItemChange = (index: number, itemValue: Source) => {
+ const newSources = value.map((item, i) => (i === index ? itemValue : item));
+ onChange(newSources);
+ };
+
+ const handleAddItem = () => {
+ const newSources = [...value, { key: '', uri: '', contentType: '' }];
+ onChange(newSources);
+ };
+
+ const handleRemoveItem = (index: number) => {
+ const newSources = value.filter((_, i) => i !== index);
+ onChange(newSources);
+ };
+
+ return (
+
+ {value.map((source, index) => (
+
+ ))}
+
+
+
+
+ );
+};
+
+export default SourceArrayInput;
diff --git a/src/components/custom-object-form/asset-input/source-input.tsx b/src/components/custom-object-form/asset-input/source-input.tsx
new file mode 100644
index 0000000..f6ab047
--- /dev/null
+++ b/src/components/custom-object-form/asset-input/source-input.tsx
@@ -0,0 +1,83 @@
+// src/components/attribute-input/source-input.tsx
+
+import React from 'react';
+import Grid from '@commercetools-uikit/grid';
+import TextInput from '@commercetools-uikit/text-input';
+import NumberInput from '@commercetools-uikit/number-input';
+import { CloseIcon } from '@commercetools-uikit/icons';
+import Text from '@commercetools-uikit/text';
+import SecondaryButton from '@commercetools-uikit/secondary-button';
+import Spacings from '@commercetools-uikit/spacings';
+import Card from '@commercetools-uikit/card';
+import type { Source } from './types';
+
+type Props = {
+ value: Source;
+ index: number;
+ onChange: (index: number, value: Source) => void;
+ onRemove: (index: number) => void;
+};
+
+const SourceInput: React.FC = ({ value, index, onChange, onRemove }) => {
+ const handleChange = (e: React.ChangeEvent) => {
+ const { name, value: fieldValue } = e.target;
+ onChange(index, { ...value, [name]: fieldValue });
+ };
+
+ const handleNumberChange = (e: React.ChangeEvent) => {
+ const { name, value: fieldValue } = e.target;
+ onChange(index, {
+ ...value,
+ [name]: fieldValue ? parseInt(fieldValue, 10) : null,
+ });
+ };
+
+ return (
+
+
+ Sources {index + 1}
+ }
+ label="Remove Source"
+ size="small"
+ data-testid={`remove-source-${index}`}
+ onClick={() => onRemove(index)}
+ />
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default SourceInput;
diff --git a/src/components/custom-object-form/asset-input/types.ts b/src/components/custom-object-form/asset-input/types.ts
new file mode 100644
index 0000000..e98ccbf
--- /dev/null
+++ b/src/components/custom-object-form/asset-input/types.ts
@@ -0,0 +1,18 @@
+export type LocalizedString = Record;
+
+export interface Source {
+ key: string;
+ uri: string;
+ contentType: string;
+ width?: number | null;
+ height?: number | null;
+}
+
+export interface Asset {
+ key?: string;
+ name: LocalizedString;
+ description?: LocalizedString;
+ tags?: string[];
+ folder?: string;
+ sources?: Source[];
+}
diff --git a/src/components/custom-object-form/attribute-input.tsx b/src/components/custom-object-form/attribute-input.tsx
index c071f7a..f79165d 100644
--- a/src/components/custom-object-form/attribute-input.tsx
+++ b/src/components/custom-object-form/attribute-input.tsx
@@ -19,6 +19,7 @@ import { TYPES } from '../../constants';
import nestedStyles from '../container-form/nested-attributes.module.css';
import AttributeField from './attribute-field'; // eslint-disable-line import/no-cycle
import LexicalEditorField from './lexical-editor-field';
+import AssetInput from './asset-input/asset-input';
type Props = {
type: string;
@@ -271,7 +272,9 @@ const AttributeInput: FC = ({
}}
/>
{touched && errors && (
- {errors}
+
+ {errors}
+
)}
);
@@ -307,6 +310,25 @@ const AttributeInput: FC = ({
);
+ case TYPES.Asset:
+ return (
+
+
+ {touched && errors && (
+
+ {typeof errors === 'string' ? errors : 'Invalid Asset data'}
+
+ )}
+
+ );
+
default:
return null;
}
diff --git a/src/constants.ts b/src/constants.ts
index 0fd24dd..f5d28d2 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -37,6 +37,7 @@ export const TYPES = {
Object: 'Object',
Reference: 'Reference',
RichText: 'RichText',
+ Asset: 'Asset',
};
export enum TYPES_ENUM {
@@ -53,6 +54,7 @@ export enum TYPES_ENUM {
Object = 'Object',
Reference = 'Reference',
RichText = 'RichText',
+ Asset= 'Asset'
}
export const REFERENCE_BY = {