Table of contents
Definition
Status | DEVELOPED |
RBIberia Owner | Paula |
RBI Owner | Semih |
Open questions
We need to constantly make this section become empty.
Requirements
Problem statement
When listing the weekday opening hours of the restaurants is difficult for the user to see if it is open at the moment.
Acceptance criteria
The client can differentiate the current day from other days of the week
The customer can identify whether the restaurant is open or closed at the time of search
Success metrics
N/A
Important information
The hours are turned following the next rules:
First, will be returned Drive Thru hour from the store, if Drive Thru there isn’t:
Will be return Curbside hours from the store, if Curbside there isn’t:
Will be Dining Room hours from the store.
After change the hours from the store, we will need to wait 20 or 30 minutes to reflect the changes to Sanity;
Solution
Users can see five different statuses of the current day for a store:
Open Now: the store is open at the moment;
Closed Now: the store is closed at the moment, but it has opening hours on the current day;
Closed Today: the store is closed through the entire day, it doesn‘t open on that day;
Opens at: the store is closed at the moment but will open in 60 minutes or less;
Closes at: the store is open but will close in 60 minutes or less.
The statuses should be updated on these screens:
Potential
Highlight the current day:
Design
Figma design here: Figma design
Development
Task 1 – Create structure for new component
path:
intl-whitelabel-app/workspaces/frontend/src/components/store-status
store-status
__fixtures__
__tests__
index.test.tsx
use-store-status.test.ts
index.tsx
styled.ts
types.ts
use-store-status.ts
Create types
path:
intl-whitelabel-app/workspaces/frontend/src/components/store-status/types.ts
export enum StoreStatus { OpenNow = 'openNow', ClosedNow = 'closedNow', ClosedToday = 'closedToday', OpensAtTime = 'opensAtTime', ClosesAtTime = 'closesAtTime', } export interface IStoreStatus { openingHours: string; closingHours: string; dayWeek: string; dateNow: Date; } export type DateStatus = Date | undefined;
Task 2—Create translations
path:
intl-whitelabel-app/workspaces/frontend/src/state/translations/en.json
"openNow": "Open Now", "closedNow": "Closed Now", "closedToday": "Closed Today", "opensAtTime": "Opens at", "closesAtTime": "Closes at",
Add this translation on confluence page: /wiki/spaces/IN/pages/4071392004
Task 3—Create a method to format the store open and close time to date
path:
intl-whitelabel-app/workspaces/frontend/src/components/store-status/utils.ts
formatStoreHourToDate(date: Date, hour: string): Date | undefined
Example:
import { add, format } from 'date-fns'; export const getDateTimeFromStore = (date: Date, hours: string): Date | undefined => { if (!hours) { return; } return new Date(`${date.getFullYear()}.${date.getMonth() + 1}.${date.getDate()} ${hours}`); };
Task 4—Create method to return what the store status
path:
intl-whitelabel-app/workspaces/frontend/src/components/store-status/utils.ts
getIdStatus(today: Date, openDate: DateStatus, closeDate: DateStatus): StoreStatus | undefined
Open Now: the store is open at the moment;
Closed Now: the store is closed at the moment, but it has opening hours on the current day;
Closed Today: the store is closed through the entire day, it doesn‘t open on that day;
Opens at: the store is closed at the moment but will open in 60 minutes or less;
Closes at: the store is open but will close in 60 minutes or less.
Example:
import { add, format } from 'date-fns'; export const getIdStatus = ( today: Date, openDate: DateStatus, closeDate: DateStatus ): StoreStatus | undefined => { const existDates = !openDate && !closeDate; if (existDates) { return StoreStatus.ClosedToday; } const isOpen = today >= openDate! && today <= closeDate!; const isOpenAt = today <= openDate! && add(new Date(today), { hours: 1 }) >= openDate!; const isClose = today <= openDate! || today >= closeDate!; const isCloseAt = today <= closeDate! && add(new Date(today), { hours: 1 }) >= closeDate!; if (isCloseAt) { return StoreStatus.ClosesAtTime; } if (isOpen) { return StoreStatus.OpenNow; } if (isOpenAt) { return StoreStatus.OpensAtTime; } if (isClose) { return StoreStatus.ClosedNow; } return undefined; };
Task 5—Create method to set the hour on label
path:
intl-whitelabel-app/workspaces/frontend/src/components/store-status/utils.ts
setHourOnMessage = (idStatus: StoreStatus | undefined, message: string, openDate: DateStatus, closeDate: DateStatus): string
Example:
import { add, format } from 'date-fns'; export const setHourOnMessage = ( idStatus: StoreStatus | undefined, message: string, openDate: DateStatus, closeDate: DateStatus ): string => { if (idStatus === StoreStatus.ClosedToday) { return message; } else if (message && idStatus === StoreStatus.OpensAtTime) { return `${message} ${format(openDate!, 'hh aaa')}`; } else if (message && idStatus === StoreStatus.ClosesAtTime) { return `${message} ${format(closeDate!, 'hh aaa')}`; } else { return message; } };
Task 6—Create feature flag
Task 7—Create component
path:
intl-whitelabel-app/workspaces/frontend/src/components/store-status/index.tsx
https://www.figma.com/file/sfH3mHXoEUfHbm5qMul0Vn/Popeyes?node-id=39-8977&t=BxgOcMjlu01NUFWf-0
// created on type export interface IStoreStatus { openingHours: string; closingHours: string; dayWeek: string; dateNow: Date; } StoreStatus = (props: IStoreStatus)
dateNow: current dateopeningHours
: date that the store will openclosingHours
: date that the store will closedayWeek
: Day of the week. e.g:monday
,tuesday
…sunday
Example:
import React from 'react'; import { format } from 'date-fns'; import { useIntl } from 'react-intl'; import { IStoreStatus } from './types'; import { getDateTimeFromStore, getIdStatus, setHourOnMessage } from './utils'; const StoreStatus = (props: IStoreStatus) => { const { formatMessage } = useIntl(); const { openingHours, closingHours, dateNow, dayWeek } = props; const week = format(dateNow, 'iiii').toLowerCase(); if (dayWeek.toLowerCase() === week) { const openingDate = getDateTimeFromStore(dateNow, openingHours); const closingDate = getDateTimeFromStore(dateNow, closingHours); const idStatus = getIdStatus(dateNow, openingDate, closingDate); const labelStatus = idStatus ? formatMessage({ id: idStatus }) : ''; return ( <div> <span>{setHourOnMessage(idStatus, labelStatus, openingDate, closingDate)}</span> </div> ); } return <></>; }; export default StoreStatus;
for smalls layouts the status will break the line
“For the layout colors, we can use styled-components props to implement the variations based on the status. A way to do that:
Create a string variable with the status and pass it to the styled component tag. Inside the styles file, we can use this variable to choose the color and etc.
We can use flex and other CSS approaches to make the line break of the text but if difficult we can use the available media screens in the project to set different values in the CSS.”
We will export the const
storeHoursSummary
tointl-whitelabel-app/workspaces/frontend/src/pages/store-locator/new-ui/store-card/constants.ts
path:
intl-whitelabel-app/workspaces/frontend/src/components/store-info-modal/index.tsx
export const storeHoursSummary: [string, string][] = [ ['monday', 'mon'], ['tuesday', 'tue'], ['wednesday', 'wed'], ['thursday', 'thr'], ['friday', 'fri'], ['saturday', 'sat'], ['sunday', 'sun'], ];
Task 8—Add new the component on
store-info-modal
componentpath:
intl-whitelabel-app/workspaces/frontend/src/components/store-info-modal/index.tsx
Add the new component on component
Hours
We will format the layout to get like this:
Task 9—Add new the component on
store card
componentWe will need to return the operation hour, Then, we will change the hook
useOpenClosedText
:path:
intl-whitelabel-app/workspaces/frontend/src/pages/store-locator/new-ui/store-card/hooks/use-open-closed-text.ts
interface IOpenClosedText { isOpen: boolean; text: string; operatingHours?: object; } const getHoursToday = (operatingHours: IOperatingHours) => { const today = format(new Date(), 'iiii').toLowerCase(); const hoursToday = storeHoursSummary .filter(([weekName]) => weekName.toLowerCase() === today) .map(([, weekAbbreviated]) => { const openingHours = operatingHours[`${weekAbbreviated}Open`]; const closingHours = operatingHours[`${weekAbbreviated}Close`]; return { openingHours, closingHours }; }); return hoursToday; }; export const useOpenClosedText = (restaurant: IRestaurantNode): IOpenClosedText => { const { availablePickupServiceModes } = useServiceModeStatus(restaurant); const { formatMessage } = useIntl(); // Get the open hours for the pickup service mode that is open and not disabled. const [operatingHours] = availablePickupServiceModes.map(getOperatingHours(restaurant)); if (!operatingHours) { return { isOpen: false, text: formatMessage({ id: 'closed' }) }; } const [hours] = getHoursToday(operatingHours); if (isWithinOneHourOfClose(operatingHours)) { return { isOpen: true, text: formatMessage({ id: 'closesAt' }, { time: readableCloseHourToday(operatingHours) }), operatingHours: hours, }; } return { isOpen: true, text: formatMessage({ id: 'open' }), operatingHours: hours }; };
On file:
intl-whitelabel-app/workspaces/frontend/src/pages/store-locator/new-ui/store-card/store-card.tsx
, we will return theoperatingHours
on hookuseOpenClosedText
const { isOpen, text, operatingHours } = useOpenClosedText(restaurant); <StoreCardView ... storeDetails={{ ... operatingHours ... }} />
We will change the type
StoreDetails
path:
intl-whitelabel-app/workspaces/frontend/src/pages/store-locator/new-ui/store-card/store-card.view.tsx
type StoreDetails = { ... operatingHours?: object; };
On the same file, we will add the new component inside component
StoreCardCaption
0 Comments