Skip to content

Commit

Permalink
Added DateTime and FromNow components
Browse files Browse the repository at this point in the history
  • Loading branch information
EricWittmann committed Nov 30, 2023
1 parent cd3f544 commit 364e20f
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 0 deletions.
45 changes: 45 additions & 0 deletions lib/common/DateTime.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { FunctionComponent, useEffect, useState } from "react";
import { DateTime as LuxonDateTime, LocaleOptions } from "luxon";

/**
* Properties
*/
export type DateTimeProps = {
date: Date | string | undefined;
format?: string;
locale?: string;
};

export const DateTime: FunctionComponent<DateTimeProps> = (props: DateTimeProps) => {
const [formattedDate, setFormattedDate] = useState<string | null>(null);

const format: string = props.format || "locale";

useEffect(() => {
let luxonDT: LuxonDateTime | undefined = undefined;
if (props.date && typeof props.date === "string") {
luxonDT = LuxonDateTime.fromISO(props.date as string);
} else if (props.date && typeof props.date === "object") {
luxonDT = LuxonDateTime.fromJSDate(props.date as Date);
}

if (luxonDT) {
const localeOptions: LocaleOptions = {
locale: props.locale
};
if (format === "fromNow") {
setFormattedDate(luxonDT.toRelative());
} else if (format === "locale") {
setFormattedDate(luxonDT.toLocaleString(LuxonDateTime.DATETIME_FULL, localeOptions));
} else {
setFormattedDate(luxonDT.toFormat(format, localeOptions));
}
} else {
setFormattedDate(null);
}
}, [props.date]);

return (
<span>{ formattedDate || "" }</span>
);
};
14 changes: 14 additions & 0 deletions lib/common/FromNow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { FunctionComponent } from "react";
import { DateTime } from "./DateTime.tsx";


export type FromNowProps = {
date: Date | string | undefined;
};


export const FromNow: FunctionComponent<FromNowProps> = (props: FromNowProps) => {
return (
<DateTime date={props.date} format="fromNow" />
);
};
4 changes: 4 additions & 0 deletions lib/common/ObjectDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type ObjectDropdownProps = {
onSelect: (value: any | undefined) => void;
itemToString: (value: any) => string;
itemIsDivider?: (value: any) => boolean;
itemIsVisible?: (value: any) => boolean;
itemToTestId?: (value: any) => string;
noSelectionLabel?: string;
menuAppendTo?: HTMLElement | (() => HTMLElement) | "inline";
Expand Down Expand Up @@ -89,6 +90,9 @@ export const ObjectDropdown: FunctionComponent<ObjectDropdownProps> = (props: Ob
<DropdownList>
{
props.items.map((item, index) => {
if (props.itemIsVisible !== undefined && !props.itemIsVisible(item)) {
return <></>;
}
return (
(props.itemIsDivider && props.itemIsDivider(item)) ?
<Divider component="li" key={`divider-${index}`} />
Expand Down
18 changes: 18 additions & 0 deletions lib/common/ToggleIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { FunctionComponent } from "react";
import { ChevronDownIcon, ChevronRightIcon } from "@patternfly/react-icons";

/**
* Properties
*/
export type ToggleIconProps = {
expanded: boolean;
onClick: () => void;
};

export const ToggleIcon: FunctionComponent<ToggleIconProps> = ({ expanded, onClick }: ToggleIconProps) => {
return expanded ? (
<ChevronDownIcon onClick={onClick} style={{ cursor: "pointer" }} />
) : (
<ChevronRightIcon onClick={onClick} style={{ cursor: "pointer" }} />
);
};
3 changes: 3 additions & 0 deletions lib/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
export * from "./DateTime";
export * from "./FromNow";
export * from "./If";
export * from "./IfNotEmpty";
export * from "./IfNotLoading";
export * from "./ListWithToolbar";
export * from "./ObjectDropdown";
export * from "./ObjectSelect";
export * from "./ToggleIcon";
export * from "./UrlUpload";
12 changes: 12 additions & 0 deletions src/AllDemos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { AppAboutModalDemo } from "./demos/AppAboutModalDemo.tsx";
import { ListWithToolbarDemo } from "./demos/ListWithToolbarDemo.tsx";
import { UrlUploadDemo } from "./demos/UrlUploadDemo.tsx";
import { ResponsiveTableDemo } from "./demos/ResponsiveTableDemo.tsx";
import { ToggleIconDemo } from "./demos/ToggleIconDemo.tsx";
import { DateTimeDemo } from "./demos/DateTimeDemo.tsx";

export type Demo = {
name: string;
Expand All @@ -23,6 +25,11 @@ export type Demos = {

export const ALL_DEMOS: Demos = {
"Common Types": [
{
name: "DateTime",
description: "Component to display a string or Date object in a UI, with different formatting options.",
component: <DateTimeDemo/>
},
{
name: "If",
description: "Wraps some children and shows them only when the condition is true.",
Expand Down Expand Up @@ -53,6 +60,11 @@ export const ALL_DEMOS: Demos = {
description: "An easier way to model a select input of objects. This differs from a dropdown, which is a menu. This component is an input.",
component: <ObjectSelectDemo/>
},
{
name: "ToggleIcon",
description: "A simple toggle icon, used to expand/collapse a UI section.",
component: <ToggleIconDemo/>
},
{
name: "UrlUpload",
description: "A component similar to the Patternfly FileUpload, but meant for choosing URLs instead of files.",
Expand Down
63 changes: 63 additions & 0 deletions src/demos/DateTimeDemo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { FunctionComponent } from "react";
import { DateTime } from "../../lib/common";
import { Card, CardBody, CardTitle } from "@patternfly/react-core";

export const DateTimeDemo: FunctionComponent<any> = () => {
return (
<div>
<Card ouiaId="NowCard">
<CardTitle>Now</CardTitle>
<CardBody>
<div>
<DateTime date={new Date()} />
</div>
<div>
<DateTime date={new Date()} format="locale" />
</div>
<div>
<DateTime date={new Date()} format="fromNow" />
</div>
<div>
<DateTime date={new Date()} format="yyyy-MM-dd 'at' h:mm a" />
</div>
</CardBody>
</Card>
<div style={{ padding: "15px" }} />
<Card ouiaId="Jan17Card">
<CardTitle>Jan 17, 2012 @ 3:30 PM (UTC)</CardTitle>
<CardBody>
<div>
<DateTime date="2012-01-17T15:30:00Z" />
</div>
<div>
<DateTime date="2012-01-17T15:30:00Z" format="locale" />
</div>
<div>
<DateTime date="2012-01-17T15:30:00Z" format="fromNow" />
</div>
<div>
<DateTime date="2012-01-17T15:30:00Z" format="yyyy-MM-dd 'at' h:mm a" />
</div>
</CardBody>
</Card>
<div style={{ padding: "15px" }} />
<Card ouiaId="Feb10Card">
<CardTitle>Feb 10, 2023 @ 02:15 AM (UTC)</CardTitle>
<CardBody>
<div>
<DateTime date="2023-02-10T02:15:00Z" />
</div>
<div>
<DateTime date="2023-02-10T02:15:00Z" format="locale" />
</div>
<div>
<DateTime date="2023-02-10T02:15:00Z" format="fromNow" />
</div>
<div>
<DateTime date="2023-02-10T02:15:00Z" format="yyyy-MM-dd 'at' h:mm a" />
</div>
</CardBody>
</Card>
</div>
);
};
17 changes: 17 additions & 0 deletions src/demos/ToggleIconDemo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { FunctionComponent, useState } from "react";
import { Card, CardBody } from "@patternfly/react-core";
import { ToggleIcon } from "../../lib/common";

export const ToggleIconDemo: FunctionComponent<any> = () => {
const [isExpanded, setIsExpanded] = useState(false);

return (
<div>
<Card ouiaId="ToggleIconDemo">
<CardBody>
<ToggleIcon expanded={isExpanded} onClick={() => setIsExpanded(!isExpanded)} />
</CardBody>
</Card>
</div>
);
};
2 changes: 2 additions & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export default defineConfig({
"react",
"react-dom",
"react/jsx-runtime",
"luxon",
"use-resize-observer",
"@patternfly/patternfly",
"@patternfly/react-core",
"@patternfly/react-icons",
Expand Down

0 comments on commit 364e20f

Please sign in to comment.