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

[React][Next.js] DateField empty value is not treated as empty #1836

Merged
merged 3 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Our versioning strategy is as follows:

* `[templates/nextjs]` `[templates/react]` `[templates/vue]` `[templates/angular]` Changed formatting in temp/config to prevent parse issues in Unix systems ([#1787](https://github.com/Sitecore/jss/pull/1787))([#1791](https://github.com/Sitecore/jss/pull/1791))
* `[templates/nextjs-sxa]` The banner variant of image component is fixed with supporting metadata mode. ([#1826](https://github.com/Sitecore/jss/pull/1826))
* `[sitecore-jss]` `[sitecore-jss-react]` DateField empty value is not treated as empty ([#1836](https://github.com/Sitecore/jss/pull/1836))

### 🎉 New Features & Improvements

Expand Down
135 changes: 93 additions & 42 deletions packages/sitecore-jss-react/src/components/Date.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { mount, shallow } from 'enzyme';
import React from 'react';
import { DateField } from './Date';
import { describe } from 'node:test';
import { EMPTY_DATE_FIELD_VALUE } from '@sitecore-jss/sitecore-jss/layout';

describe('<DateField />', () => {
it('should return null if no editable or value', () => {
Expand Down Expand Up @@ -116,48 +117,98 @@ describe('<DateField />', () => {
);
});

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

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

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 is empty', () => {
const field = {
value: '',
metadata: testMetadata,
};

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

const rendered = mount(
<DateField 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('')
);
describe('empty value', () => {
describe('Should render default component', () => {
it('field value is empty string', () => {
const field = {
value: '',
metadata: testMetadata,
};

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

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('field value is default empty date value', () => {
const field = {
value: EMPTY_DATE_FIELD_VALUE,
metadata: testMetadata,
};

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

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('')
);
});
});

describe('Should render custom component', () => {
it('field value is empty string', () => {
const field = {
value: '',
metadata: testMetadata,
};

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

const rendered = mount(
<DateField 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('field value is defaule empty date value', () => {
const field = {
value: EMPTY_DATE_FIELD_VALUE,
metadata: testMetadata,
};

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

const rendered = mount(
<DateField 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 empty, when editing is explicitly disabled ', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { mount } from 'enzyme';
import { withEmptyFieldEditingComponent } from './withEmptyFieldEditingComponent';
import { DefaultEmptyFieldEditingComponentText } from '../components/DefaultEmptyFieldEditingComponents';
import { describe } from 'node:test';
import { EMPTY_DATE_FIELD_VALUE } from '@sitecore-jss/sitecore-jss/layout';

describe('withEmptyFieldEditingComponent', () => {
describe('Metadata', () => {
Expand Down Expand Up @@ -165,6 +166,65 @@ describe('withEmptyFieldEditingComponent', () => {
expect(rendered.html()).to.equal('<div><h1>hi</h1><h2>foo</h2><p>bar</p></div>');
});

describe('Date', () => {
it('Should render component if field value is provided', () => {
const props = {
field: {
metadata: testMetadata,
value: '2024-01-01T00:00:00Z',
},
};

const WrappedComponent = withEmptyFieldEditingComponent<TestComponentProps>(TestComponent, {
defaultEmptyFieldEditingComponent: DefaultEmptyFieldEditingComponentText,
});

const rendered = mount(<WrappedComponent {...props} />);
expect(rendered.html()).to.equal('<div><h1>hi</h1><h2>foo</h2><p>bar</p></div>');
});

it('Should render default empty component if field value is empty', () => {
const props = {
field: {
value: EMPTY_DATE_FIELD_VALUE,
metadata: testMetadata,
},
};

const WrappedComponent = withEmptyFieldEditingComponent<TestComponentProps>(TestComponent, {
defaultEmptyFieldEditingComponent: DefaultEmptyFieldEditingComponentText,
});

const rendered = mount(<WrappedComponent {...props} />);
const expected = mount(<DefaultEmptyFieldEditingComponentText />);

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

it('Should render custom empty component if field value is empty', () => {
const EmptyFieldEditingComponent: React.FC = () => (
<span className="empty-field-value-placeholder">Custom Empty field value</span>
);

const props = {
field: {
value: EMPTY_DATE_FIELD_VALUE,
metadata: testMetadata,
},
emptyFieldEditingComponent: EmptyFieldEditingComponent,
};

const WrappedComponent = withEmptyFieldEditingComponent<TestComponentProps>(TestComponent, {
defaultEmptyFieldEditingComponent: DefaultEmptyFieldEditingComponentText,
});

const rendered = mount(<WrappedComponent {...props} />);
const expected = mount(<EmptyFieldEditingComponent />);

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

describe('Image', () => {
it('Should render component if field src is provided', () => {
const props = {
Expand Down
7 changes: 6 additions & 1 deletion packages/sitecore-jss/src/layout/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ export {
FieldMetadata,
} from './models';

export { getFieldValue, getChildPlaceholder, isFieldValueEmpty } from './utils';
export {
getFieldValue,
getChildPlaceholder,
isFieldValueEmpty,
EMPTY_DATE_FIELD_VALUE,
} from './utils';

export { getContentStylesheetLink } from './content-styles';

Expand Down
30 changes: 29 additions & 1 deletion packages/sitecore-jss/src/layout/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/* eslint-disable no-unused-expressions */
import { expect } from 'chai';
import { ComponentRendering } from '../../layout';
import { getFieldValue, getChildPlaceholder, isFieldValueEmpty } from './utils';
import {
getFieldValue,
getChildPlaceholder,
isFieldValueEmpty,
EMPTY_DATE_FIELD_VALUE,
} from './utils';

describe('sitecore-jss layout utils', () => {
describe('getFieldValue', () => {
Expand Down Expand Up @@ -153,6 +158,29 @@ describe('sitecore-jss layout utils', () => {
});
});

describe('Date', () => {
it('should return true if Date field is empty', () => {
expect(
isFieldValueEmpty({
value: EMPTY_DATE_FIELD_VALUE,
})
).to.be.true;
expect(
isFieldValueEmpty({
value: '',
})
).to.be.true;
});

it('should return false if Date field is not empty', () => {
const field = {
value: '2024-01-01T00:00:00Z',
};
const result = isFieldValueEmpty(field);
expect(result).to.be.false;
});
});

describe('boolean', () => {
it('should return false if field value is boolean false', () => {
const field = {
Expand Down
9 changes: 8 additions & 1 deletion packages/sitecore-jss/src/layout/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ export function getChildPlaceholder(
return rendering.placeholders[placeholderName];
}

/**
* The default value for an empty Date field.
* This value is defined as a default one by .NET
*/
export const EMPTY_DATE_FIELD_VALUE = '0001-01-01T00:00:00Z';

/**
* Determines if the passed in field object's value is empty.
* @param {GenericFieldValue | Partial<Field>} field the field object.
Expand All @@ -91,6 +97,7 @@ export function isFieldValueEmpty(field: GenericFieldValue | Partial<Field>): bo
!(fieldValue as { [key: string]: unknown }).src;
const isLinkFieldEmpty = (fieldValue: GenericFieldValue) =>
!(fieldValue as { [key: string]: unknown }).href;
const isDateFieldEmpty = (fieldValue: GenericFieldValue) => fieldValue === EMPTY_DATE_FIELD_VALUE;

const isEmpty = (fieldValue: GenericFieldValue) => {
if (typeof fieldValue === 'object') {
Expand All @@ -103,7 +110,7 @@ export function isFieldValueEmpty(field: GenericFieldValue | Partial<Field>): bo
// Avoid returning true for 0 and false values
return false;
} else {
return !fieldValue;
return !fieldValue || isDateFieldEmpty(fieldValue);
}
};

Expand Down