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

STCOM-849 wrong day of week #1583

Merged
merged 7 commits into from
Jul 8, 2021
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
7 changes: 6 additions & 1 deletion .storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import frTranslations from '../translations/stripes-components/fr.json';
import huTranslations from '../translations/stripes-components/hu.json';
import itTranslations from '../translations/stripes-components/it_IT.json';
import ptTranslations from '../translations/stripes-components/pt_BR.json';
import ruTranslations from '../translations/stripes-components/ru.json';
import svTranslations from '../translations/stripes-components/sv.json';


// mimics the StripesTranslationPlugin in @folio/stripes-core
function prefixKeys(obj) {
Expand All @@ -44,11 +47,13 @@ const messages = {
hu: prefixKeys(huTranslations),
it: prefixKeys(itTranslations),
pt: prefixKeys(ptTranslations),
ru: prefixKeys(ruTranslations),
sv: prefixKeys(svTranslations),
};

// Set intl configuration
setIntlConfig({
locales: ['ar', 'ca', 'da', 'de', 'en', 'es', 'fr', 'hu', 'it', 'pt'],
locales: ['ar', 'ca', 'da', 'de', 'en', 'es', 'fr', 'hu', 'it', 'pt', 'ru', 'sv'],
defaultLocale: 'en',
getMessages: (locale) => messages[locale]
});
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Add link icon. Refs STCOM-852.
* `<MultiColumnList>` add ability to focus component if content data is empty. Refs STCOM-851.
* Expose getLocaleDateFormat Datepicker util. Refs STCOM-854.
* Fix issue with misaligned dates/weekdays in Datepicker Calendar. Refs STCOM-849

## [9.2.0](https://github.com/folio-org/stripes-components/tree/v9.2.0) (2021-06-08)
[Full Changelog](https://github.com/folio-org/stripes-components/compare/v9.1.0...v9.2.0)
Expand Down
55 changes: 42 additions & 13 deletions lib/Datepicker/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ import MonthSelect from './MonthSelect';
import css from './Calendar.css';

import staticFirstWeekday from './staticFirstWeekDay';
import staticRegions from './staticLangCountryCodes';

const moment = extendMoment(Moment);

function getCalendar(year, month) {
function getCalendar(year, month, offset) {
const startDate = moment([year, month]);
const firstDay = moment(startDate).startOf('month');
const endDay = moment(startDate).endOf('month');
Expand All @@ -36,8 +37,8 @@ function getCalendar(year, month) {
if (weeks.indexOf(ref) < 0) {
weeks.push(mo.week());
const endClone = moment(mo);
rowStartArray.push(mo.weekday(0));
rowEndArray.push(endClone.weekday(6));
rowStartArray.push(mo.weekday(offset + 0));
rowEndArray.push(endClone.weekday(offset + 6));
}
});

Expand Down Expand Up @@ -119,7 +120,7 @@ class Calendar extends React.Component {
constructor(props) {
super(props);

moment.locale(this.props.locale);
moment.locale(this.props.intl.locale || this.props.locale);

const { selectedDate, dateFormat } = this.props;

Expand All @@ -135,6 +136,27 @@ class Calendar extends React.Component {
cursorDate = new moment(); // eslint-disable-line new-cap
}

// if the stripes locale has no region (only 2 letters), it needs to be normalized to a
// common form of {language}-{region} ex: "en-SE" (english spoken in Sweden)
// We adjust it by mapping from a set of common default regions (staticRegions);
// the first weekday in calendar rendering is derived from region.
// Hopefully it will be implemented in browser Intl API soon..
// but until then...

let dayOffset = 0;
let adjustedLocale = props.intl.locale || props.locale;
if (adjustedLocale.length === 2) {
const regionDefault = staticRegions[adjustedLocale];
adjustedLocale = `${adjustedLocale}-${regionDefault}`;
}

// if moment doesn't have the requested locale from above (intl/stripes), it falls back to 'en'. If this
// is the case, we need to set an offset value for correct calendar day rendering -
// otherwise, the calendar columns will be off, resulting misaligned weekdays/calendar days.
if (moment.locale() === 'en') {
dayOffset = getFirstWeekday(adjustedLocale);
}

const base = new moment(cursorDate); // eslint-disable-line new-cap
const month = base.month();
const year = base.year();
Expand All @@ -147,17 +169,22 @@ class Calendar extends React.Component {
date: this.selectedMoment,
month,
year,
calendar: getCalendar(year, month)
calendar: getCalendar(year, month),
dayOffset,
};

this.weekDays = getWeekDays(props.intl);
this.months = getMonths(props.intl);
this.firstWeekDay = getFirstWeekday(props.intl.locale);
this.firstWeekDay = getFirstWeekday(adjustedLocale);
this.firstField = props.firstFieldRef;
this.calendarGrid = React.createRef();
}

static getDerivedStateFromProps(nextProps, prevState) {
const {
dayOffset
} = prevState;

// When the selected date has changed, update the state with it
let stateUpdate;
if (nextProps.selectedDate !== prevState.selectedDate) {
Expand All @@ -172,7 +199,7 @@ class Calendar extends React.Component {
date: moDate,
month,
year,
calendar: getCalendar(year, month),
calendar: getCalendar(year, month, dayOffset),
selectedDate: nextProps.selectedDate,
dateFormat: nextProps.dateFormat,
};
Expand All @@ -185,7 +212,7 @@ class Calendar extends React.Component {
date: fallbackDate,
month,
year,
calendar: getCalendar(year, month),
calendar: getCalendar(year, month, dayOffset),
selectedDate: nextProps.selectedDate,
dateFormat: nextProps.dateFormat,
};
Expand All @@ -195,7 +222,7 @@ class Calendar extends React.Component {
if (stateUpdate) {
const newState = prevState;
Object.assign(newState, stateUpdate);
newState.calendar = getCalendar(newState.year, newState.month);
newState.calendar = getCalendar(newState.year, newState.month, dayOffset);
return newState;
} else {
return null;
Expand Down Expand Up @@ -271,7 +298,7 @@ class Calendar extends React.Component {
newState.month = newState.cursorDate.month();
newState.year = newState.cursorDate.year();
if (newState.year !== oldState.year || newState.month !== oldState.month) {
newState.calendar = getCalendar(newState.year, newState.month);
newState.calendar = getCalendar(newState.year, newState.month, oldState.dayOffset);
}
return newState;
}, () => {
Expand Down Expand Up @@ -325,6 +352,7 @@ class Calendar extends React.Component {
const month = parseInt(e.target.value, 10);

this.setState(curState => {
const { dayOffset } = curState;
let cursorDate = '';
if (month === this.selectedMoment?.month()) {
cursorDate = this.selectedMoment;
Expand All @@ -333,7 +361,7 @@ class Calendar extends React.Component {
}
return {
month,
calendar: getCalendar(curState.year, month),
calendar: getCalendar(curState.year, month, dayOffset),
cursorDate,
};
});
Expand All @@ -345,7 +373,7 @@ class Calendar extends React.Component {
if (new moment(year, 'YYYY', true).isValid()) { // eslint-disable-line new-cap
this.setState(curState => ({
year,
calendar: getCalendar(year, curState.month),
calendar: getCalendar(year, curState.month, curState.dayOffset),
}));
}
}
Expand All @@ -359,14 +387,15 @@ class Calendar extends React.Component {

moveDate = (op, unit) => {
this.setState(curState => {
const { dayOffset } = curState;
const newDate = curState.date[op](1, unit);
const month = newDate.month();
const year = newDate.year();
return {
date: newDate,
month,
year,
calendar: getCalendar(year, month)
calendar: getCalendar(year, month, dayOffset)
};
});
}
Expand Down
151 changes: 151 additions & 0 deletions lib/Datepicker/staticLangCountryCodes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// Export a 'default' mapping using ISO-396-1 culture codes.
// This is used to convert 2-letter locales (language-only) to 4-letter locales.
// containing region information (used to derive first-day-of-week)

export default {
af: 'ZA',
sq: 'AL',
gsw: 'FR',
am: 'ET',
ar: 'SA',
hy: 'AM',
as: 'IN',
az: 'AZ',
bn: 'IN',
ba: 'RU',
eu: 'ES',
be: 'BY',
bs: 'BA',
br: 'FR',
bg: 'BG',
my: 'MM',
ca: 'ES',
ku: 'IQ',
chr: 'US',
zh: 'CN',
co: 'FR',
hr: 'HR',
cs: 'CZ',
da: 'DK',
prs: 'AF',
dv: 'MV',
nl: 'NL',
dz: 'BT',
bin: 'NG',
en: 'US',
et: 'EE',
fo: 'FO',
fil: 'PH',
fi: 'FI',
fr: 'FR',
fy: 'NL',
ff: 'NG',
gl: 'ES',
ka: 'GE',
de: 'DE',
el: 'GR',
kl: 'GL',
gn: 'PY',
gu: 'IN',
ha: 'NG',
haw: 'US',
he: 'IL',
hi: 'IN',
hu: 'HU',
ibb: 'NG',
is: 'IS',
ig: 'NG',
id: 'ID',
iu: 'CA',
ga: 'IE',
xh: 'ZA',
zu: 'ZA',
it: 'IT',
ja: 'JP',
kn: 'IN',
kr: 'NG',
ks: 'IN',
kk: 'KZ',
km: 'KH',
quc: 'GT',
rw: 'RW',
sw: 'KE',
kok: 'IN',
ko: 'KR',
ky: 'KG',
lo: 'LA',
la: '001',
lv: 'LV',
lt: 'LT',
dsb: 'DE',
lb: 'LU',
mk: 'MK',
ms: 'MY',
ml: 'IN',
mt: 'MT',
mni: 'IN',
mi: 'NZ',
arn: 'CL',
mr: 'IN',
moh: 'CA',
mn: 'MN',
ne: 'NP',
nb: 'NO',
nn: 'NO',
oc: 'FR',
or: 'IN',
om: 'ET',
pap: '029',
ps: 'AF',
fa: 'IR',
pl: 'PL',
pt: 'PT',
pa: 'IN',
quz: 'BO',
ro: 'RO',
rm: 'CH',
ru: 'RU',
sah: 'RU',
smn: 'FI',
smj: 'SE',
se: 'NO',
sms: 'FI',
sma: 'SE',
sa: 'IN',
gd: 'GB',
sr: 'RS',
nso: 'ZA',
tn: 'ZA',
sd: 'PK',
si: 'LK',
sk: 'SK',
sl: 'SI',
so: 'SO',
st: 'ZA',
es: 'ES',
sv: 'SE',
syr: 'SY',
tg: 'TJ',
tzm: 'DZ',
ta: 'IN',
tt: 'RU',
te: 'IN',
th: 'TH',
bo: 'CN',
ti: 'ER',
ts: 'ZA',
tr: 'TR',
tk: 'TM',
uk: 'UA',
hsb: 'DE',
ur: 'PK',
ug: 'CN',
uz: 'UZ',
ve: 'ZA',
vi: 'VN',
cy: 'GB',
wo: 'SN',
ii: 'CN',
yi: '001',
yo: 'NG'
};