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

[sitecore-jss-react] [sitecore-jss-nextjs] Default Placeholder Content for empty fields in editMode metadata #1831

Merged
merged 25 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
de2dc7c
default empty field editing placeholder for text field component
yavorsk Jun 23, 2024
e01330f
add withEmptyPlaceholderValue HOC; unit tests; default empty field ed…
yavorsk Jun 24, 2024
c0d4681
modify Date, Image, RichText react components to use withEmptyValueEd…
yavorsk Jun 24, 2024
32bfea9
update Link, NextImage, RichText nextjs fields components to work wit…
yavorsk Jun 24, 2024
be9b0be
add proptype for custom empty value placeholder component prop
yavorsk Jun 24, 2024
2fd41cc
added comments, fixed lint errors
yavorsk Jun 24, 2024
801ebf6
fix lint errors
yavorsk Jun 25, 2024
237d1bd
reexport default empty field editing components and withEmptyValueEdi…
yavorsk Jun 25, 2024
c1164a7
renamings HOC, properties - withEmptyFieldEditingComponent
yavorsk Jun 27, 2024
79a0b4e
update hasValue logic
yavorsk Jun 27, 2024
085e09b
react field components - extract common properties into EditableField…
yavorsk Jul 1, 2024
aca9f14
introduce a function fieldValueIsEmpty in base packages and use it in…
yavorsk Jul 4, 2024
881362c
fix lint error
yavorsk Jul 4, 2024
54f0282
fix lint errors
yavorsk Jul 4, 2024
abbb0d7
introduced FieldMetadata interface in core package; use it accross fi…
yavorsk Jul 5, 2024
a1edea7
update withEmptyEditingComponent hoc to accept single options parameter
yavorsk Jul 5, 2024
6a94a33
add unit tests for isValueEmpty; isValueEmpty update
yavorsk Jul 5, 2024
052fc3b
isFieldValueEmpty - account for boolean value; add additional code co…
yavorsk Jul 5, 2024
74960b3
isEmptyField refactoring and unit tests update
yavorsk Jul 8, 2024
48a2af2
unit tests update
yavorsk Jul 8, 2024
62bf073
update emptyFieldComponent prop proptype; use isFieldValueEmpty in fi…
yavorsk Jul 8, 2024
2a05d7c
update nextjs Link and NextImage unit tests, small updates
yavorsk Jul 8, 2024
534a0f2
some test title updates
yavorsk Jul 8, 2024
b669ab5
add additional check for metadata for isEditing var in next richtext
yavorsk Jul 8, 2024
f18852a
add clarifying comment
yavorsk Jul 8, 2024
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
187 changes: 162 additions & 25 deletions packages/sitecore-jss-nextjs/src/components/Link.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { mount } from 'enzyme';
import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime';
import { Link } from './Link';
import { spy } from 'sinon';
import { describe } from 'node:test';

const Router = (): NextRouter => ({
pathname: '/',
Expand Down Expand Up @@ -361,7 +362,7 @@ describe('<Link />', () => {
expect(rendered).to.have.length(0);
});

it('should render field metadata component when metadata property is present', () => {
describe('editMode metadata', () => {
const testMetadata = {
contextItem: {
id: '{09A07660-6834-476C-B93B-584248D3003B}',
Expand All @@ -374,29 +375,165 @@ describe('<Link />', () => {
rawValue: 'Test1',
};

const field = {
value: {
href: '/lorem',
text: 'ipsum',
class: 'my-link',
},
metadata: testMetadata,
};

const rendered = mount(
<Page>
<Link field={field} />
</Page>
);

expect(rendered.html()).to.equal(
[
`<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
testMetadata
)}</code>`,
'<a href="/lorem" class="my-link">ipsum</a>',
'<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
].join('')
);
it('should render field metadata component when metadata property is present', () => {
const field = {
value: {
href: '/lorem',
text: 'ipsum',
class: 'my-link',
},
metadata: testMetadata,
};

const rendered = mount(
<Page>
<Link field={field} />
</Page>
);

expect(rendered.html()).to.equal(
[
`<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
testMetadata
)}</code>`,
'<a href="/lorem" class="my-link">ipsum</a>',
'<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
].join('')
);
});

it('should render default empty field component when field value href is not present', () => {
const field = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Need to add a test case to cover: when field is the value itself (GenericFIeldValue) type (applicable for rest of unit tests below)

value: {
href: undefined,
},
metadata: testMetadata,
};

const rendered = mount(
<Page>
<Link field={field} />
</Page>
);

expect(rendered.html()).to.equal(
[
`<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
testMetadata
)}</code>`,
'<span>[No text in field]</span>',
'<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
].join('')
);
});

it('should render default empty field component when field href is not present', () => {
const field = {
href: undefined,
metadata: testMetadata,
};

const rendered = mount(
<Page>
<Link field={field} />
</Page>
);

expect(rendered.html()).to.equal(
[
`<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
testMetadata
)}</code>`,
'<span>[No text in field]</span>',
'<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
].join('')
);
});

it('should render custom empty field component when provided, when field value href is not present', () => {
const field = {
value: {
href: undefined,
},
metadata: testMetadata,
};

const EmptyFieldEditingComponent: React.FC = () => (
<span className="empty-field-value-placeholder">Custom Empty field value</span>
);

const rendered = mount(
<Page>
<Link field={field} emptyFieldEditingComponent={EmptyFieldEditingComponent} />
</Page>
);

expect(rendered.html()).to.equal(
[
`<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
testMetadata
)}</code>`,
'<span class="empty-field-value-placeholder">Custom Empty field value</span>',
'<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
].join('')
);
});

it('should render custom empty field component when provided, when field href is not present', () => {
const field = {
href: undefined,
metadata: testMetadata,
};

const EmptyFieldEditingComponent: React.FC = () => (
<span className="empty-field-value-placeholder">Custom Empty field value</span>
);

const rendered = mount(
<Page>
<Link field={field} emptyFieldEditingComponent={EmptyFieldEditingComponent} />
</Page>
);

expect(rendered.html()).to.equal(
[
`<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
testMetadata
)}</code>`,
'<span class="empty-field-value-placeholder">Custom Empty field value</span>',
'<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
].join('')
);
});

it('should render nothing when field value href is not present and editing is explicitly disabled', () => {
const field = {
value: { href: undefined },
metadata: testMetadata,
};

const rendered = mount(
<Page>
<Link field={field} editable={false} />
</Page>
);

expect(rendered.html()).to.equal('');
});

it('should render nothing when field href is not present and editing is explicitly disabled', () => {
const field = {
href: undefined,
metadata: testMetadata,
};

const rendered = mount(
<Page>
<Link field={field} editable={false} />
</Page>
);

expect(rendered.html()).to.equal('');
});
});
});
8 changes: 6 additions & 2 deletions packages/sitecore-jss-nextjs/src/components/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,19 @@ export const Link = forwardRef<HTMLAnchorElement, LinkProps>(

if (
!field ||
(!(field as LinkFieldValue).editable && !field.value && !(field as LinkFieldValue).href)
(!(field as LinkFieldValue).editable &&
!field.value &&
!(field as LinkFieldValue).href &&
!field.metadata)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to add a metadata check in other components? For example Next.js RichText component, it has a similar check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

where is the similar check for nextjs RichText? (link does not show it). I think we don't need it for RichText - we don't have similar 'return null' as it is in here in Link.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see. i added it

) {
return null;
}

const value = ((field as LinkFieldValue).href
? field
: (field as LinkField).value) as LinkFieldValue;
const { href, querystring, anchor } = value;
// fallback to {} if value is undefined; could happen if field is LinkFieldValue, href is empty in metadata mode
const { href, querystring, anchor } = value || {};
illiakovalenko marked this conversation as resolved.
Show resolved Hide resolved

const isEditing =
editable && ((field as LinkFieldValue).editable || (field as LinkFieldValue).metadata);
Expand Down
149 changes: 132 additions & 17 deletions packages/sitecore-jss-nextjs/src/components/NextImage.test.tsx
yavorsk marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import chaiString from 'chai-string';
import { mount } from 'enzyme';
import React from 'react';
import { NextImage } from './NextImage';
import { ImageField } from '@sitecore-jss/sitecore-jss-react';
import {
ImageField,
DefaultEmptyFieldEditingComponentImage,
} from '@sitecore-jss/sitecore-jss-react';
import { ImageLoader } from 'next/image';
import { spy, match } from 'sinon';
import sinonChai from 'sinon-chai';
Expand Down Expand Up @@ -287,7 +290,7 @@ describe('<NextImage />', () => {
});
});

it('should render field metadata component when metadata property is present', () => {
describe('editMode metadata', () => {
const testMetadata = {
contextItem: {
id: '{09A07660-6834-476C-B93B-584248D3003B}',
Expand All @@ -300,21 +303,133 @@ describe('<NextImage />', () => {
rawValue: 'Test1',
};

const field = {
value: { src: '/assets/img/test0.png', alt: 'my image' },
metadata: testMetadata,
};
it('should render field metadata component when metadata property is present', () => {
const field = {
value: { src: '/assets/img/test0.png', alt: 'my image' },
metadata: testMetadata,
};

const rendered = mount(<NextImage field={field} fill={true} />);

expect(rendered.html()).to.equal(
[
`<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
testMetadata
)}</code>`,
'<img alt="my image" loading="lazy" decoding="async" data-nimg="fill" style="position: absolute; height: 100%; width: 100%; left: 0px; top: 0px; right: 0px; bottom: 0px; color: transparent;" sizes="100vw" srcset="/_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=3840&amp;q=75">',
'<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
].join('')
);
});

it('should render default empty field component for Image when field value src is not present', () => {
const field = {
value: {},
metadata: testMetadata,
};

const rendered = mount(<NextImage field={field} />);
const defaultEmptyImagePlaceholder = mount(<DefaultEmptyFieldEditingComponentImage />);
expect(rendered.html()).to.equal(
[
`<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
testMetadata
)}</code>`,
defaultEmptyImagePlaceholder.html(),
'<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
].join('')
);
});

it('should render default empty field component for Image when field src is not present', () => {
const field = {
src: undefined,
metadata: testMetadata,
};

const rendered = mount(<NextImage field={field} />);
const defaultEmptyImagePlaceholder = mount(<DefaultEmptyFieldEditingComponentImage />);
expect(rendered.html()).to.equal(
[
`<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
testMetadata
)}</code>`,
defaultEmptyImagePlaceholder.html(),
'<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
].join('')
);
});

it('should render custom empty field component when provided, when field value src is not present', () => {
const field = {
value: {},
metadata: testMetadata,
};

const EmptyFieldEditingComponent: React.FC = () => (
<span className="empty-field-value-placeholder">Custom Empty field value</span>
);

const rendered = mount(
<NextImage field={field} emptyFieldEditingComponent={EmptyFieldEditingComponent} />
);

expect(rendered.html()).to.equal(
[
`<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
testMetadata
)}</code>`,
'<span class="empty-field-value-placeholder">Custom Empty field value</span>',
'<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
].join('')
);
});

it('should render custom empty field component when provided, when field src is not present', () => {
const field = {
src: undefined,
metadata: testMetadata,
};

const rendered = mount(<NextImage field={field} fill={true} />);

expect(rendered.html()).to.equal(
[
`<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
testMetadata
)}</code>`,
'<img alt="my image" loading="lazy" decoding="async" data-nimg="fill" style="position: absolute; height: 100%; width: 100%; left: 0px; top: 0px; right: 0px; bottom: 0px; color: transparent;" sizes="100vw" srcset="/_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=640&amp;q=75 640w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=750&amp;q=75 750w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=828&amp;q=75 828w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=1080&amp;q=75 1080w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=1200&amp;q=75 1200w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=1920&amp;q=75 1920w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=2048&amp;q=75 2048w, /_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=%2Fassets%2Fimg%2Ftest0.png&amp;w=3840&amp;q=75">',
'<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
].join('')
);
const EmptyFieldEditingComponent: React.FC = () => (
<span className="empty-field-value-placeholder">Custom Empty field value</span>
);

const rendered = mount(
<NextImage field={field} emptyFieldEditingComponent={EmptyFieldEditingComponent} />
);

expect(rendered.html()).to.equal(
[
`<code type="text/sitecore" chrometype="field" class="scpm" kind="open">${JSON.stringify(
testMetadata
)}</code>`,
'<span class="empty-field-value-placeholder">Custom Empty field value</span>',
'<code type="text/sitecore" chrometype="field" class="scpm" kind="close"></code>',
].join('')
);
});

it('should render nothing when field value is not present, when editing is explicitly disabled', () => {
const field = {
value: {},
metadata: testMetadata,
};

const rendered = mount(<NextImage field={field} editable={false} />);

expect(rendered.html()).to.equal('');
});

it('should render nothing when field src is not present, when editing is explicitly disabled', () => {
const field = {
src: undefined,
metadata: testMetadata,
};

const rendered = mount(<NextImage field={field} editable={false} />);

expect(rendered.html()).to.equal('');
});
});
});
Loading