Skip to content

Commit

Permalink
Merge branch 'main' into PANGOO-2581
Browse files Browse the repository at this point in the history
  • Loading branch information
kerrie625 authored Sep 18, 2024
2 parents ec83984 + 5c41040 commit cbdcbd7
Show file tree
Hide file tree
Showing 2 changed files with 200 additions and 5 deletions.
22 changes: 17 additions & 5 deletions packages/bpk-component-datepicker/src/BpkDatepicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*/

import { createRef, Component } from 'react';
import type { ReactElement} from 'react';
import type { ReactElement, RefObject } from 'react';

import BpkBreakpoint, { BREAKPOINTS } from '../../bpk-component-breakpoint';
import {
Expand All @@ -33,13 +33,15 @@ import {
import BpkInput, { withOpenEvents } from '../../bpk-component-input';
import BpkModal from '../../bpk-component-modal';
import BpkPopover from '../../bpk-component-popover';
import { setNativeValue } from '../../bpk-react-utils';

import type {
DaysOfWeek,
ReactComponent,
SelectionConfiguration,
} from '../../bpk-component-calendar';


const Input = withOpenEvents(BpkInput);

const DefaultCalendar = withCalendarState(
Expand All @@ -62,7 +64,7 @@ type Props = {
id: string;
title: string;
/**
* Because this component uses a modal on mobile viewports, you need to let it know what
* Because this component uses a modal on mobile viewports, you need to let it know what
* the root element of your application is by returning its DOM node via this prop
* This is to "hide" your application from screen readers whilst the datepicker is open.
* The "pagewrap" element id is a convention we use internally at Skyscanner. In most cases it should "just work".
Expand Down Expand Up @@ -107,7 +109,11 @@ type State = {
};

class BpkDatepicker extends Component<Props, State> {
inputRef: React.RefObject<HTMLInputElement>;
inputRef: (ref:HTMLInputElement) => void;

elementRef?: HTMLInputElement;

focusRef?: RefObject<HTMLInputElement>;

static defaultProps = {
calendarComponent: DefaultCalendar,
Expand Down Expand Up @@ -140,7 +146,10 @@ class BpkDatepicker extends Component<Props, State> {
this.state = {
isOpen: props.isOpen!,
};
this.inputRef = createRef();
this.focusRef = createRef();
this.inputRef = (ref) => {
this.elementRef = ref
}
}

componentDidUpdate(prevProps: Props, prevState: State) {
Expand Down Expand Up @@ -269,7 +278,9 @@ class BpkDatepicker extends Component<Props, State> {
DateUtils.isSameDay(newEndDate, selectionConfiguration.startDate))
) {
onDateSelect(selectionConfiguration.startDate, newEndDate);
this.elementRef && setNativeValue(this.elementRef, this.props.formatDate(newEndDate));
} else {
this.elementRef && setNativeValue(this.elementRef, this.props.formatDate(newStartDate));
onDateSelect(newStartDate);
}
}
Expand Down Expand Up @@ -312,8 +323,9 @@ class BpkDatepicker extends Component<Props, State> {
delete rest.isOpen;

const input = inputComponent || (
<div ref={this.inputRef} >
<div ref={this.focusRef} >
<Input
inputRef={this.inputRef}
id={id}
name={`${id}_input`}
value={this.getValue(selectionConfiguration!, formatDate)}
Expand Down
183 changes: 183 additions & 0 deletions packages/bpk-component-datepicker/src/form-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* Backpack - Skyscanner's Design System
*
* Copyright 2016 Skyscanner Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


import { useEffect, useState } from 'react';

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { CALENDAR_SELECTION_TYPE } from '../../bpk-component-calendar';
import { format } from '../../bpk-component-calendar/src/date-utils';
import {
weekDays,
formatMonth,
formatDateFull,
} from '../../bpk-component-calendar/test-utils';

import BpkDatepicker from './BpkDatepicker';

const formatDate = (date: Date) => format(date, 'dd/MM/yyyy');

const inputProps = {
onChange: () => null,
placeholder: 'placeholder',
large: true,
};

describe('BpkDatepicker form test', () => {
it('should work as a form component in a form', async () => {
const Wrap = () => (
<form data-testid="form">
<BpkDatepicker
id="datepicker"
closeButtonText="Close"
daysOfWeek={weekDays}
changeMonthLabel="Change month"
previousMonthLabel="Go to previous month"
nextMonthLabel="Go to next month"
title="Departure date"
weekStartsOn={1}
getApplicationElement={() => document.createElement('div')}
formatDate={formatDate}
formatMonth={formatMonth}
formatDateFull={formatDateFull}
inputProps={inputProps}
selectionConfiguration={{
type: CALENDAR_SELECTION_TYPE.single,
date: new Date(2020, 2, 19),
}}
data-testid="myDatepicker"
/>
</form>
);
render(<Wrap />);

const inputField = screen.getByRole('textbox', {
name: /19th March 2020/i,
});
await userEvent.click(inputField);

const formData = new FormData(
screen.getByTestId('form') as HTMLFormElement,
);
expect(Object.fromEntries(formData.entries())).toEqual({ datepicker_input: '19/03/2020' });
});

it('should work as a form component in a form for two way trip', async () => {
const Wrap = () => (
<form data-testid="form">
<BpkDatepicker
id="datepicker"
closeButtonText="Close"
daysOfWeek={weekDays}
changeMonthLabel="Change month"
previousMonthLabel="Go to previous month"
nextMonthLabel="Go to next month"
title="Departure date"
weekStartsOn={1}
getApplicationElement={() => document.createElement('div')}
formatDate={formatDate}
formatMonth={formatMonth}
formatDateFull={formatDateFull}
inputProps={inputProps}
selectionConfiguration={{
type: CALENDAR_SELECTION_TYPE.range,
startDate: new Date(2020, 2, 19),
endDate: new Date(2020, 3, 19),
}}
data-testid="myDatepicker"
/>
</form>
);
render(<Wrap />);

const inputField = screen.getByRole('textbox', {
name: /19th March 2020/i,
});
await userEvent.click(inputField);

const formData = new FormData(
screen.getByTestId('form') as HTMLFormElement,
);
expect(Object.fromEntries(formData.entries())).toEqual({ datepicker_input: '19/03/2020 - 19/04/2020' });
});

it('should emit a change event when input is changed', async () => {
const formValidation = jest.fn();
const Wrap = () => {
const [calendarDate, setCalendarDate] = useState(new Date(2020, 2, 19));
useEffect(() => {
document.addEventListener('change', formValidation);
}, []);
return (
<form data-testid="form">
<BpkDatepicker
id="datepicker"
closeButtonText="Close"
daysOfWeek={weekDays}
changeMonthLabel="Change month"
previousMonthLabel="Go to previous month"
nextMonthLabel="Go to next month"
title="Departure date"
weekStartsOn={1}
getApplicationElement={() => document.createElement('div')}
formatDate={formatDate}
formatMonth={formatMonth}
formatDateFull={formatDateFull}
inputProps={inputProps}
minDate={new Date(2020, 2, 1)}
maxDate={new Date(2020, 2, 31)}
onDateSelect={(date1, date2) => {
setCalendarDate(date1);
}}
selectionConfiguration={{
type: CALENDAR_SELECTION_TYPE.single,
date: calendarDate,
}}
data-testid="myDatepicker"
/>
</form>
);
};

render(<Wrap />);

const inputField = screen.getByRole('textbox', {
name: /Thursday, 19th March 2020/i,
});

await userEvent.click(inputField);

const calendarDialog = screen.getByRole('dialog', {
name: 'Departure date',
});

expect(calendarDialog).toBeInTheDocument();

const dateButton = screen.getByRole('button', {
name: /30/i,
});

await userEvent.click(dateButton);

expect(inputField.getAttribute('value')).toEqual('30/03/2020');
expect(formValidation).toHaveBeenCalledTimes(1);
});
});

0 comments on commit cbdcbd7

Please sign in to comment.