keystonejs / keystone-5

https://v5.keystonejs.com
MIT License
64 stars 33 forks source link

CalendarDay field is causing reload (refresh) of the whole page after clicking on "next month" arrow #355

Open Yair-Ohana opened 3 years ago

Yair-Ohana commented 3 years ago

Describe the bug

basically, when clicking on the next/previous month buttons (image attached) reload is triggered (?!). The weird part is that it only happens on production, not locally.

To Reproduce

  1. Be sure to configure a CalendarDay field.
  2. Go to the Admin UI.
  3. Click on the next/previous month arrow.

Expected behavior

Clicking on one of the arrows will trigger an event that moving to the next/previous month.

Screenshots

image

System information

Happens on chrome. Using "@keystonejs/fields": "21.0.0",

Huge thanks.

stale[bot] commented 3 years ago

It looks like there hasn't been any activity here in over 6 months. Sorry about that! We've flagged this issue for special attention. It wil be manually reviewed by maintainers, not automatically closed. If you have any additional information please leave us a comment. It really helps! Thank you for you contribution. :)

Brandyweb commented 2 years ago

Reading the source code and managed to replicate the element but solving the error. I have solved I am using a custom input, to correct the refresh of the page when I change the month.

In any folder you want in my case server create a call CustomFields.

There I create a folder called CalendarDay with 3 files.

Field.js

/** @jsx jsx */
/* eslint-disable react/react-in-jsx-scope, jsx-a11y/no-autofocus */
import { jsx } from '@emotion/core';
import 'react-day-picker/dist/style.css';
import { DayPicker } from "react-day-picker";
import { Input } from '@arch-ui/input';
import { Alert } from '@arch-ui/alert';
import { FieldContainer, FieldLabel, FieldDescription, FieldInput } from '@arch-ui/fields';
import { parseISO, compareAsc, formatISO, isValid } from 'date-fns';

const CalendarDayField = ({ autoFocus, field, value, errors, onChange, isDisabled }) => {
    const htmlID = `ks-daypicker-${field.path}`;
    const handleDayClick = day => onChange(formatISO(day, { representation: 'date' }));

    return (
        <FieldContainer>
            <FieldLabel htmlFor={htmlID} field={field} errors={errors} />
            <FieldDescription text={field.adminDoc} />
            <FieldInput>
                <DayPicker
                    disabled={[
                        day =>
                            isDisabled ||
                            (field.config.dateTo && compareAsc(day, parseISO(field.config.dateTo)) === 1) ||
                            (field.config.dateTo && compareAsc(parseISO(field.config.dateFrom), day) === 1),
                    ]}
                    selected={isValid(parseISO(value)) ? parseISO(value) : undefined}
                    defaultMonth={isValid(parseISO(value)) ? parseISO(value) : undefined}
                    onDayClick={handleDayClick}
                />
            </FieldInput>

            <FieldInput>
                <Input
                    id={htmlID}
                    autoFocus={autoFocus}
                    onKeyDown={e => {
                        // There is a strange bug where after interacting with the day picker
                        // and then pressing enter on the input the value is changed to the start
                        // of the month. I think this is bug with the day picker.
                        // The following is a work-around:
                        if (e.key === 'Enter') {
                            e.preventDefault();
                        }
                    }}
                    onChange={e => {
                        // Tiny bit of date format normalisation for convenience
                        const normalisedValue = e.target.value.replace('/', '-').replace('\\', '-');
                        const parsedValue = parseISO(normalisedValue);
                        if (normalisedValue.length === 10 && isValid(parsedValue)) {
                            handleDayClick(parsedValue);
                        } else {
                            onChange(normalisedValue);
                        }
                    }}
                    disabled={isDisabled}
                    css={{ color: isValid(parseISO(value)) ? undefined : 'darkred' }}
                    value={value}
                />
            </FieldInput>

            {errors.map(({ message, data }) => (
                <Alert appearance="danger" key={message}>
                    {message}
                    {data ? ` - ${JSON.stringify(data)}` : null}
                </Alert>
            ))}
        </FieldContainer>
    );
};

export default CalendarDayField;

Implementation.js

const { CalendarDay } = require('@keystonejs/fields');

// Using the text implementation because we're going to stringify the array of results.
// We could store this in another table, but this would require writing a complex controller.
// JSON.stringify feels good enough for this simple field.

module.exports = {
    Implementation: CalendarDay.implementation,
    MongoIntegerInterface: CalendarDay.adapters.mongoose,
    KnexIntegerInterface: CalendarDay.adapters.knex,
};

index.js

const { Implementation, MongoIntegerInterface, KnexIntegerInterface } = require('./Implementation');

module.exports = {
    type: 'CustomCalendarDay',
    implementation: Implementation,
    views: {
        Controller: require.resolve('@keystonejs/fields/types/CalendarDay/views/Controller/dist/fields.cjs'),
        Field: require.resolve('./Field'),
        Filter: require.resolve('@keystonejs/fields/types/CalendarDay/views/Filter/dist/fields.cjs'),
        Cell: require.resolve('@keystonejs/fields/types/CalendarDay/views/Cell/dist/fields.cjs'),
    },
    adapters: {
        mongoose: MongoIntegerInterface,
        knex: KnexIntegerInterface,
    },
};

Now use in Models

const CalendarDay = require('../server/CustomField/CalendarDay')

module.exports = {
    fields: {
        date: {
            type: CalendarDay
        }
    }
};

NOTE: Install "react-day-picker": "8.0.0-beta.37" from npm install react-day-picker@8.0.0-beta.37