@bloom-housing/ui-components 6.0.0 → 6.0.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +236 -7
- package/index.ts +1 -0
- package/package.json +3 -5
- package/src/actions/Button.tsx +1 -0
- package/src/actions/LinkButton.tsx +1 -0
- package/src/blocks/FormCard.scss +1 -0
- package/src/blocks/HousingCounselor.tsx +8 -3
- package/src/blocks/ImageCard.tsx +24 -13
- package/src/blocks/MediaCard.docs.mdx +37 -0
- package/src/blocks/MediaCard.scss +10 -11
- package/src/blocks/MediaCard.tsx +4 -4
- package/src/blocks/StandardCard.tsx +1 -1
- package/src/blocks/StatusItem.tsx +17 -6
- package/src/forms/DOBField.tsx +20 -8
- package/src/forms/DateField.tsx +16 -7
- package/src/forms/Dropzone.scss +7 -0
- package/src/forms/Dropzone.tsx +18 -5
- package/src/forms/Field.tsx +5 -0
- package/src/forms/FieldGroup.tsx +14 -3
- package/src/forms/HouseholdMemberForm.tsx +4 -1
- package/src/forms/HouseholdSizeField.tsx +16 -6
- package/src/forms/TimeField.tsx +15 -6
- package/src/global/custom_counter.scss +1 -1
- package/src/global/forms.scss +38 -5
- package/src/global/headers.scss +1 -1
- package/src/global/markdown.scss +2 -2
- package/src/global/vendor/ag_grid.scss +43 -9
- package/src/headers/Hero.tsx +8 -1
- package/src/headers/PageHeader.scss +3 -2
- package/src/headers/PageHeader.tsx +5 -1
- package/src/headers/SiteHeader.tsx +11 -4
- package/src/helpers/formOptions.tsx +4 -1
- package/src/helpers/formatYesNoLabel.ts +8 -6
- package/src/locales/es.json +1 -1
- package/src/locales/general.json +9 -4
- package/src/locales/tl.json +1 -1
- package/src/locales/vi.json +1 -1
- package/src/locales/zh.json +1 -1
- package/src/navigation/Breadcrumbs.scss +1 -0
- package/src/navigation/Breadcrumbs.tsx +1 -1
- package/src/navigation/FooterNav.tsx +5 -1
- package/src/navigation/LanguageNav.tsx +1 -1
- package/src/navigation/ProgressNav.docs.mdx +47 -0
- package/src/navigation/ProgressNav.scss +101 -56
- package/src/navigation/ProgressNav.tsx +45 -15
- package/src/navigation/SideNav.scss +56 -0
- package/src/navigation/SideNav.tsx +2 -2
- package/src/navigation/TabNav.scss +1 -1
- package/src/navigation/TabNav.tsx +1 -1
- package/src/navigation/Tabs.scss +25 -6
- package/src/notifications/AlertBox.docs.mdx +41 -0
- package/src/notifications/AlertBox.scss +78 -41
- package/src/notifications/AlertBox.tsx +20 -14
- package/src/notifications/SiteAlert.tsx +3 -0
- package/src/notifications/StatusMessage.tsx +8 -2
- package/src/notifications/alertTypes.ts +1 -0
- package/src/overlays/Modal.scss +3 -1
- package/src/page_components/ApplicationTimeline.scss +6 -6
- package/src/page_components/ApplicationTimeline.tsx +17 -7
- package/src/page_components/NavigationHeader.tsx +10 -10
- package/src/page_components/forgot-password/FormForgotPassword.tsx +1 -1
- package/src/page_components/listing/AdditionalFees.tsx +1 -1
- package/src/page_components/listing/ListingCard.scss +4 -0
- package/src/page_components/listing/ListingCard.tsx +18 -3
- package/src/page_components/listing/listing_sidebar/Contact.tsx +2 -2
- package/src/page_components/listing/listing_sidebar/GetApplication.tsx +31 -16
- package/src/page_components/listing/listing_sidebar/ListingUpdated.tsx +5 -1
- package/src/page_components/listing/listing_sidebar/OrDivider.tsx +4 -2
- package/src/page_components/listing/listing_sidebar/ReferralApplication.tsx +7 -4
- package/src/page_components/listing/listing_sidebar/events/DownloadLotteryResults.tsx +6 -1
- package/src/page_components/sign-in/FormSignIn.tsx +1 -1
- package/src/page_components/sign-in/FormSignInErrorBox.tsx +1 -1
- package/src/sections/InfoCardGrid.scss +1 -1
- package/src/sections/InfoCardGrid.tsx +4 -1
- package/src/sections/ListSection.tsx +1 -1
- package/src/tables/AgTable.tsx +56 -26
- package/src/tables/StandardTable.tsx +19 -7
- package/src/text/Tag.scss +7 -0
- package/src/text/Tag.tsx +2 -0
|
@@ -5,7 +5,7 @@ import { StackedTable, StackedTableProps } from "../../tables/StackedTable"
|
|
|
5
5
|
import { StandardTable, StandardTableProps } from "../../tables/StandardTable"
|
|
6
6
|
import { Heading, HeaderType } from "../../headers/Heading"
|
|
7
7
|
import { Tag } from "../../text/Tag"
|
|
8
|
-
import { AppearanceStyleType } from "../../global/AppearanceTypes"
|
|
8
|
+
import { AppearanceShadeType, AppearanceStyleType } from "../../global/AppearanceTypes"
|
|
9
9
|
import { Icon, IconFillColors } from "../../icons/Icon"
|
|
10
10
|
import "./ListingCard.scss"
|
|
11
11
|
import { NavigationContext } from "../../config/NavigationContext"
|
|
@@ -16,6 +16,8 @@ export interface CardHeader {
|
|
|
16
16
|
content: string | React.ReactNode
|
|
17
17
|
href?: string
|
|
18
18
|
customClass?: string
|
|
19
|
+
styleType?: AppearanceStyleType
|
|
20
|
+
isPillType?: boolean
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
export interface FooterButton {
|
|
@@ -74,12 +76,25 @@ const ListingCard = (props: ListingCardProps) => {
|
|
|
74
76
|
const getHeader = (
|
|
75
77
|
header: CardHeader | undefined,
|
|
76
78
|
priority: number,
|
|
77
|
-
|
|
79
|
+
styleType?: HeaderType,
|
|
78
80
|
customClass?: string
|
|
79
81
|
) => {
|
|
80
82
|
if (header && header.content) {
|
|
83
|
+
if (header.isPillType) {
|
|
84
|
+
return (
|
|
85
|
+
<Tag
|
|
86
|
+
className="listings-pill_header"
|
|
87
|
+
pillStyle
|
|
88
|
+
capitalized
|
|
89
|
+
styleType={header.styleType}
|
|
90
|
+
shade={AppearanceShadeType.light}
|
|
91
|
+
>
|
|
92
|
+
{header.content}
|
|
93
|
+
</Tag>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
81
96
|
return (
|
|
82
|
-
<Heading priority={priority} style={
|
|
97
|
+
<Heading priority={priority} style={styleType} className={customClass}>
|
|
83
98
|
{header.href ? (
|
|
84
99
|
<LinkComponent className="is-card-link" href={header.href}>
|
|
85
100
|
{header.content}
|
|
@@ -95,12 +95,12 @@ const Contact = ({
|
|
|
95
95
|
|
|
96
96
|
{additionalInformation?.map((info) => {
|
|
97
97
|
return (
|
|
98
|
-
<
|
|
98
|
+
<div key={info.title} className={"my-3"}>
|
|
99
99
|
<Heading priority={3} style={"sidebarSubHeader"}>
|
|
100
100
|
{info.title}
|
|
101
101
|
</Heading>
|
|
102
102
|
<div className="text-gray-800 text-tiny markdown">{info.content}</div>
|
|
103
|
-
</
|
|
103
|
+
</div>
|
|
104
104
|
)
|
|
105
105
|
})}
|
|
106
106
|
</section>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import React, { useState } from "react"
|
|
2
|
-
import
|
|
2
|
+
import Markdown from "markdown-to-jsx"
|
|
3
3
|
import { Button } from "../../../actions/Button"
|
|
4
4
|
import { LinkButton } from "../../../actions/LinkButton"
|
|
5
5
|
import { AppearanceStyleType } from "../../../global/AppearanceTypes"
|
|
6
6
|
import { Address } from "../../../helpers/MultiLineAddress"
|
|
7
|
-
import { ContactAddress } from "./ContactAddress"
|
|
8
|
-
import { OrDivider } from "./OrDivider"
|
|
9
7
|
import { Heading } from "../../../headers/Heading"
|
|
10
|
-
import
|
|
8
|
+
import { t } from "../../../helpers/translator"
|
|
9
|
+
import { OrDivider } from "./OrDivider"
|
|
10
|
+
import { ContactAddress } from "./ContactAddress"
|
|
11
11
|
|
|
12
12
|
export interface PaperApplication {
|
|
13
13
|
fileURL: string
|
|
@@ -33,6 +33,16 @@ export interface ApplicationsProps {
|
|
|
33
33
|
postmarkedApplicationsReceivedByDate?: string
|
|
34
34
|
/** Whether or not to hide actionable application buttons */
|
|
35
35
|
preview?: boolean
|
|
36
|
+
strings?: {
|
|
37
|
+
applicationsOpenInFuture?: string
|
|
38
|
+
applyOnline?: string
|
|
39
|
+
downloadApplication?: string
|
|
40
|
+
getAPaperApplication?: string
|
|
41
|
+
getDirections?: string
|
|
42
|
+
howToApply?: string
|
|
43
|
+
officeHoursHeading?: string
|
|
44
|
+
pickUpApplication?: string
|
|
45
|
+
}
|
|
36
46
|
}
|
|
37
47
|
/** Displays information regarding how to apply, including an online application link button, paper application downloads, and a paper application pickup address */
|
|
38
48
|
const GetApplication = (props: ApplicationsProps) => {
|
|
@@ -46,19 +56,22 @@ const GetApplication = (props: ApplicationsProps) => {
|
|
|
46
56
|
|
|
47
57
|
return (
|
|
48
58
|
<section className="aside-block" data-test-id="get-application-section">
|
|
49
|
-
<h2 className="text-caps-underline">
|
|
59
|
+
<h2 className="text-caps-underline">
|
|
60
|
+
{props.strings?.howToApply ?? t("listings.apply.howToApply")}
|
|
61
|
+
</h2>
|
|
50
62
|
{!props.applicationsOpen && (
|
|
51
63
|
<p className="mb-5 text-gray-700">
|
|
52
|
-
{
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
{props.strings?.applicationsOpenInFuture ??
|
|
65
|
+
t("listings.apply.applicationWillBeAvailableOn", {
|
|
66
|
+
openDate: props.applicationsOpenDate,
|
|
67
|
+
})}
|
|
55
68
|
</p>
|
|
56
69
|
)}
|
|
57
70
|
{props.applicationsOpen && props.onlineApplicationURL && (
|
|
58
71
|
<>
|
|
59
72
|
{props.preview ? (
|
|
60
73
|
<Button disabled className="w-full mb-2" data-test-id={"listing-view-apply-button"}>
|
|
61
|
-
{t("listings.apply.applyOnline")}
|
|
74
|
+
{props.strings?.applyOnline ?? t("listings.apply.applyOnline")}
|
|
62
75
|
</Button>
|
|
63
76
|
) : (
|
|
64
77
|
<LinkButton
|
|
@@ -67,7 +80,7 @@ const GetApplication = (props: ApplicationsProps) => {
|
|
|
67
80
|
href={props.onlineApplicationURL}
|
|
68
81
|
dataTestId={"listing-view-apply-button"}
|
|
69
82
|
>
|
|
70
|
-
{t("listings.apply.applyOnline")}
|
|
83
|
+
{props.strings?.applyOnline ?? t("listings.apply.applyOnline")}
|
|
71
84
|
</LinkButton>
|
|
72
85
|
)}
|
|
73
86
|
</>
|
|
@@ -76,7 +89,9 @@ const GetApplication = (props: ApplicationsProps) => {
|
|
|
76
89
|
{props.applicationsOpen && props.paperMethod && !!props.paperApplications?.length && (
|
|
77
90
|
<>
|
|
78
91
|
{props.onlineApplicationURL && <OrDivider bgColor="white" />}
|
|
79
|
-
<div className="text-serif-lg">
|
|
92
|
+
<div className="text-serif-lg">
|
|
93
|
+
{props.strings?.getAPaperApplication ?? t("listings.apply.getAPaperApplication")}
|
|
94
|
+
</div>
|
|
80
95
|
<Button
|
|
81
96
|
styleType={
|
|
82
97
|
!props.preview && props.onlineApplicationURL ? AppearanceStyleType.primary : undefined
|
|
@@ -85,7 +100,7 @@ const GetApplication = (props: ApplicationsProps) => {
|
|
|
85
100
|
onClick={toggleDownload}
|
|
86
101
|
disabled={props.preview}
|
|
87
102
|
>
|
|
88
|
-
{t("listings.apply.downloadApplication")}
|
|
103
|
+
{props.strings?.downloadApplication ?? t("listings.apply.downloadApplication")}
|
|
89
104
|
</Button>
|
|
90
105
|
</>
|
|
91
106
|
)}
|
|
@@ -94,7 +109,7 @@ const GetApplication = (props: ApplicationsProps) => {
|
|
|
94
109
|
<p key={index} className="text-center mt-2 mb-4 text-sm">
|
|
95
110
|
<a
|
|
96
111
|
href={paperApplication.fileURL}
|
|
97
|
-
title={t("listings.apply.downloadApplication")}
|
|
112
|
+
title={props.strings?.downloadApplication ?? t("listings.apply.downloadApplication")}
|
|
98
113
|
target="_blank"
|
|
99
114
|
>
|
|
100
115
|
{paperApplication.languageString}
|
|
@@ -107,16 +122,16 @@ const GetApplication = (props: ApplicationsProps) => {
|
|
|
107
122
|
<OrDivider bgColor="white" />
|
|
108
123
|
)}
|
|
109
124
|
<Heading priority={3} style={"sidebarSubHeader"}>
|
|
110
|
-
{t("listings.apply.pickUpAnApplication")}
|
|
125
|
+
{props.strings?.pickUpApplication ?? t("listings.apply.pickUpAnApplication")}
|
|
111
126
|
</Heading>
|
|
112
127
|
<ContactAddress
|
|
113
128
|
address={props.applicationPickUpAddress}
|
|
114
|
-
mapString={t("t.getDirections")}
|
|
129
|
+
mapString={props.strings?.getDirections ?? t("t.getDirections")}
|
|
115
130
|
/>
|
|
116
131
|
{props.applicationPickUpAddressOfficeHours && (
|
|
117
132
|
<>
|
|
118
133
|
<Heading priority={3} style={"sidebarSubHeader"}>
|
|
119
|
-
{t("leasingAgent.officeHours")}
|
|
134
|
+
{props.strings?.officeHoursHeading ?? t("leasingAgent.officeHours")}
|
|
120
135
|
</Heading>
|
|
121
136
|
<p className="text-gray-800 text-tiny markdown">
|
|
122
137
|
<Markdown
|
|
@@ -4,6 +4,9 @@ import dayjs from "dayjs"
|
|
|
4
4
|
|
|
5
5
|
interface ListingUpdatedProps {
|
|
6
6
|
listingUpdated: Date
|
|
7
|
+
strings?: {
|
|
8
|
+
listingUpdated?: string
|
|
9
|
+
}
|
|
7
10
|
}
|
|
8
11
|
|
|
9
12
|
const ListingUpdated = (props: ListingUpdatedProps) => {
|
|
@@ -11,7 +14,8 @@ const ListingUpdated = (props: ListingUpdatedProps) => {
|
|
|
11
14
|
return (
|
|
12
15
|
<section className="aside-block">
|
|
13
16
|
<p className="text-tiny text-gray-800">
|
|
14
|
-
{
|
|
17
|
+
{props?.strings?.listingUpdated ??
|
|
18
|
+
`${t("listings.listingUpdated")}: ${dayjs(listingUpdated).format("MMMM DD, YYYY")}`}
|
|
15
19
|
</p>
|
|
16
20
|
</section>
|
|
17
21
|
)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as React from "react"
|
|
2
2
|
import { t } from "../../../helpers/translator"
|
|
3
3
|
|
|
4
|
-
const OrDivider = (props: { bgColor: string }) => (
|
|
4
|
+
const OrDivider = (props: { bgColor: string; strings?: { orString?: string } }) => (
|
|
5
5
|
<div className="aside-block__divider">
|
|
6
|
-
<span className={`bg-${props.bgColor} aside-block__conjunction`}>
|
|
6
|
+
<span className={`bg-${props.bgColor} aside-block__conjunction`}>
|
|
7
|
+
{props.strings?.orString ?? t("t.or")}
|
|
8
|
+
</span>
|
|
7
9
|
</div>
|
|
8
10
|
)
|
|
9
11
|
|
|
@@ -5,7 +5,10 @@ import { Icon, IconFillColors } from "../../../icons/Icon"
|
|
|
5
5
|
interface ReferralApplicationProps {
|
|
6
6
|
description: string
|
|
7
7
|
phoneNumber: string
|
|
8
|
-
|
|
8
|
+
strings: {
|
|
9
|
+
call?: string
|
|
10
|
+
title: string
|
|
11
|
+
}
|
|
9
12
|
}
|
|
10
13
|
|
|
11
14
|
const ReferralApplication = (props: ReferralApplicationProps) => {
|
|
@@ -13,11 +16,11 @@ const ReferralApplication = (props: ReferralApplicationProps) => {
|
|
|
13
16
|
|
|
14
17
|
return (
|
|
15
18
|
<section className="aside-block">
|
|
16
|
-
<h2 className="text-caps-underline">{props.title}</h2>
|
|
19
|
+
<h2 className="text-caps-underline">{props.strings.title}</h2>
|
|
17
20
|
<p>
|
|
18
21
|
<a href={linkedPhoneNumber}>
|
|
19
|
-
<Icon symbol="phone" size="medium" fill={IconFillColors.primary} />
|
|
20
|
-
{props.phoneNumber}
|
|
22
|
+
<Icon symbol="phone" size="medium" fill={IconFillColors.primary} />{" "}
|
|
23
|
+
{props.strings.call ?? t("t.call")} {props.phoneNumber}
|
|
21
24
|
</a>
|
|
22
25
|
</p>
|
|
23
26
|
<p className="text-tiny mt-4 text-gray-800">{props.description}</p>
|
|
@@ -5,13 +5,18 @@ type DownloadLotteryResultsProps = {
|
|
|
5
5
|
resultsDate?: string
|
|
6
6
|
buttonText?: string
|
|
7
7
|
pdfURL?: string
|
|
8
|
+
strings?: {
|
|
9
|
+
sectionHeader?: string
|
|
10
|
+
}
|
|
8
11
|
}
|
|
9
12
|
|
|
10
13
|
const DownloadLotteryResults = (props: DownloadLotteryResultsProps) => {
|
|
11
14
|
if (!props.pdfURL) return null
|
|
12
15
|
return (
|
|
13
16
|
<section className="aside-block text-center">
|
|
14
|
-
<h2 className="text-caps pb-4">
|
|
17
|
+
<h2 className="text-caps pb-4">
|
|
18
|
+
{props.strings?.sectionHeader ?? t("listings.lotteryResults.header")}
|
|
19
|
+
</h2>
|
|
15
20
|
{props.resultsDate && (
|
|
16
21
|
<p className="uppercase text-gray-800 text-tiny font-semibold pb-4">{props.resultsDate}</p>
|
|
17
22
|
)}
|
|
@@ -66,7 +66,7 @@ const FormSignIn = ({
|
|
|
66
66
|
<FormCard>
|
|
67
67
|
<div className="form-card__lead text-center">
|
|
68
68
|
<Icon size="2xl" symbol="profile" />
|
|
69
|
-
<
|
|
69
|
+
<h1 className="form-card__title">{t(`nav.signIn`)}</h1>
|
|
70
70
|
</div>
|
|
71
71
|
<FormSignInErrorBox
|
|
72
72
|
errors={errors}
|
|
@@ -27,7 +27,7 @@ const FormSignInErrorBox = ({ networkStatus, errors, errorMessageId }: FormSignI
|
|
|
27
27
|
<ErrorMessage
|
|
28
28
|
id={`form-sign-in-${errorMessageId}-error`}
|
|
29
29
|
error={!!networkStatus.content}
|
|
30
|
-
className="block mt-0 leading-normal text-
|
|
30
|
+
className="block mt-0 leading-normal text-alert"
|
|
31
31
|
>
|
|
32
32
|
<AlertBox type={"alert"} inverted onClose={() => networkStatus.reset()}>
|
|
33
33
|
{networkStatus.content.title}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from "react"
|
|
2
|
+
import { Heading } from "../headers/Heading"
|
|
2
3
|
import "./InfoCardGrid.scss"
|
|
3
4
|
|
|
4
5
|
export interface InfoCardGridProps {
|
|
@@ -10,7 +11,9 @@ export interface InfoCardGridProps {
|
|
|
10
11
|
const InfoCardGrid = (props: InfoCardGridProps) => (
|
|
11
12
|
<section className="info-cards">
|
|
12
13
|
<header className="info-cards__header">
|
|
13
|
-
<
|
|
14
|
+
<Heading style={"sidebarHeader"} priority={2} className={"text-tiny"}>
|
|
15
|
+
{props.title}
|
|
16
|
+
</Heading>
|
|
14
17
|
{props.subtitle && <p className="info-cards__subtitle">{props.subtitle}</p>}
|
|
15
18
|
</header>
|
|
16
19
|
<div className="info-cards__grid">{props.children}</div>
|
|
@@ -11,7 +11,7 @@ const ListSection = (props: ListSectionProps) => (
|
|
|
11
11
|
<li className="list-section custom-counter__item">
|
|
12
12
|
<header className="list-section__header custom-counter__header">
|
|
13
13
|
<hgroup>
|
|
14
|
-
<
|
|
14
|
+
<h3 className="custom-counter__title">{props.title}</h3>
|
|
15
15
|
<span className="custom-counter__subtitle">{props.subtitle}</span>
|
|
16
16
|
</hgroup>
|
|
17
17
|
</header>
|
package/src/tables/AgTable.tsx
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import React, { useState, useCallback, useEffect, useRef } from "react"
|
|
2
2
|
import { useForm } from "react-hook-form"
|
|
3
3
|
import { AgGridReact } from "ag-grid-react"
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
GridOptions,
|
|
6
|
+
ColumnState,
|
|
7
|
+
ColumnApi,
|
|
8
|
+
ColDef,
|
|
9
|
+
ColGroupDef,
|
|
10
|
+
GridApi,
|
|
11
|
+
} from "ag-grid-community"
|
|
5
12
|
import { AgPagination, AG_PER_PAGE_OPTIONS } from "./AgPagination"
|
|
6
13
|
import { LoadingOverlay } from "../overlays/LoadingOverlay"
|
|
7
14
|
import { Field } from "../forms/Field"
|
|
@@ -15,14 +22,19 @@ export interface ColumnOrder {
|
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
export interface AgTableProps {
|
|
18
|
-
id: string
|
|
19
25
|
config: AgTableConfig
|
|
20
26
|
data: AgTableData
|
|
21
|
-
|
|
27
|
+
id: string
|
|
28
|
+
pagination?: AgTablePagination
|
|
22
29
|
search: AgTableSearch
|
|
30
|
+
selectConfig?: AgTableSelectConfig
|
|
23
31
|
sort?: AgTableSort
|
|
24
32
|
headerContent?: React.ReactNode
|
|
25
33
|
className?: string
|
|
34
|
+
strings?: {
|
|
35
|
+
filter?: string
|
|
36
|
+
searchError?: string
|
|
37
|
+
}
|
|
26
38
|
}
|
|
27
39
|
|
|
28
40
|
export interface AgTablePagination {
|
|
@@ -32,11 +44,17 @@ export interface AgTablePagination {
|
|
|
32
44
|
setCurrentPage: React.Dispatch<React.SetStateAction<number>>
|
|
33
45
|
}
|
|
34
46
|
|
|
47
|
+
export interface AgTableSelectConfig {
|
|
48
|
+
setGridApi: React.Dispatch<React.SetStateAction<GridApi | null>>
|
|
49
|
+
updateSelectedValues: () => void
|
|
50
|
+
}
|
|
51
|
+
|
|
35
52
|
export interface AgTableConfig {
|
|
36
53
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
54
|
gridComponents?: { [p: string]: any }
|
|
38
55
|
columns: (ColDef | ColGroupDef)[]
|
|
39
56
|
totalItemsLabel: string
|
|
57
|
+
rowSelection?: boolean
|
|
40
58
|
}
|
|
41
59
|
|
|
42
60
|
export interface AgTableData {
|
|
@@ -49,6 +67,7 @@ export interface AgTableData {
|
|
|
49
67
|
|
|
50
68
|
export interface AgTableSearch {
|
|
51
69
|
setSearch: React.Dispatch<React.SetStateAction<string>>
|
|
70
|
+
showSearch?: boolean
|
|
52
71
|
}
|
|
53
72
|
|
|
54
73
|
export interface AgTableSort {
|
|
@@ -81,20 +100,21 @@ export const useAgTable = () => {
|
|
|
81
100
|
}
|
|
82
101
|
|
|
83
102
|
const AgTable = ({
|
|
84
|
-
id,
|
|
85
103
|
className,
|
|
104
|
+
config: { gridComponents, columns, totalItemsLabel, rowSelection },
|
|
105
|
+
data,
|
|
106
|
+
headerContent,
|
|
107
|
+
id,
|
|
108
|
+
selectConfig,
|
|
86
109
|
pagination,
|
|
87
|
-
search: { setSearch },
|
|
110
|
+
search: { setSearch, showSearch = true },
|
|
88
111
|
sort: { setSort } = {},
|
|
89
|
-
|
|
90
|
-
data,
|
|
91
|
-
config: { gridComponents, columns, totalItemsLabel },
|
|
112
|
+
strings,
|
|
92
113
|
}: AgTableProps) => {
|
|
93
114
|
// local storage key with column state
|
|
94
115
|
const columnStateLsKey = `column-state_${id}`
|
|
95
116
|
const defaultColDef = {
|
|
96
117
|
resizable: true,
|
|
97
|
-
maxWidth: 300,
|
|
98
118
|
}
|
|
99
119
|
|
|
100
120
|
const [gridColumnApi, setGridColumnApi] = useState<ColumnApi | null>(null)
|
|
@@ -144,7 +164,7 @@ const AgTable = ({
|
|
|
144
164
|
const debounceFilter = useRef(
|
|
145
165
|
debounce((value: string) => {
|
|
146
166
|
setSearch(value)
|
|
147
|
-
pagination
|
|
167
|
+
pagination?.setCurrentPage(1)
|
|
148
168
|
}, 500)
|
|
149
169
|
)
|
|
150
170
|
useEffect(() => {
|
|
@@ -180,33 +200,37 @@ const AgTable = ({
|
|
|
180
200
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
181
201
|
const onGridReady = (params: any) => {
|
|
182
202
|
setGridColumnApi(params.columnApi)
|
|
203
|
+
if (selectConfig?.setGridApi) {
|
|
204
|
+
selectConfig.setGridApi(params.api)
|
|
205
|
+
}
|
|
183
206
|
}
|
|
184
207
|
|
|
185
208
|
return (
|
|
186
209
|
<div className={`ag-theme-alpine ag-theme-bloom ${className || ""}`}>
|
|
187
210
|
<div className="flex justify-between flex-col md:flex-row">
|
|
188
|
-
<div className=
|
|
211
|
+
<div className={`flex flex-wrap ${showSearch ? "mb-5" : "hidden"}`}>
|
|
189
212
|
<div className="md:mr-5 w-full md:w-56">
|
|
190
213
|
<Field
|
|
191
214
|
dataTestId="ag-search-input"
|
|
192
215
|
name="filter-input"
|
|
193
|
-
label={t("t.filter")}
|
|
216
|
+
label={strings?.filter ?? t("t.filter")}
|
|
194
217
|
readerOnly={true}
|
|
195
218
|
register={register}
|
|
196
|
-
placeholder={t("t.filter")}
|
|
219
|
+
placeholder={strings?.filter ?? t("t.filter")}
|
|
197
220
|
/>
|
|
198
221
|
</div>
|
|
199
|
-
<div className="w-full md:w-auto mt-2 mb-2 md:mb-0">
|
|
222
|
+
<div className="w-full md:w-auto mt-2 md:mt-0 mb-2 md:mb-0">
|
|
200
223
|
{!validSearch && (
|
|
201
|
-
<AlertBox type="notice">
|
|
224
|
+
<AlertBox type="notice">
|
|
225
|
+
{strings?.searchError ?? t("applications.table.searchError")}
|
|
226
|
+
</AlertBox>
|
|
202
227
|
)}
|
|
203
228
|
</div>
|
|
204
229
|
</div>
|
|
205
230
|
|
|
206
231
|
{headerContent}
|
|
207
232
|
</div>
|
|
208
|
-
|
|
209
|
-
<div className="applications-table mt-5">
|
|
233
|
+
<div className="applications-table">
|
|
210
234
|
<LoadingOverlay isLoading={data.loading}>
|
|
211
235
|
<div>
|
|
212
236
|
<AgGridReact
|
|
@@ -221,19 +245,25 @@ const AgTable = ({
|
|
|
221
245
|
suppressPaginationPanel={true}
|
|
222
246
|
paginationPageSize={AG_PER_PAGE_OPTIONS[0]}
|
|
223
247
|
suppressScrollOnNewData={true}
|
|
248
|
+
rowSelection={rowSelection ? "multiple" : undefined}
|
|
249
|
+
rowMultiSelectWithClick={rowSelection}
|
|
250
|
+
onRowDataChanged={selectConfig?.updateSelectedValues ?? undefined}
|
|
251
|
+
onFirstDataRendered={selectConfig?.updateSelectedValues ?? undefined}
|
|
224
252
|
></AgGridReact>
|
|
225
253
|
</div>
|
|
226
254
|
</LoadingOverlay>
|
|
227
255
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
256
|
+
{pagination && (
|
|
257
|
+
<AgPagination
|
|
258
|
+
totalItems={data.totalItems}
|
|
259
|
+
totalPages={data.totalPages}
|
|
260
|
+
currentPage={pagination.currentPage}
|
|
261
|
+
itemsPerPage={pagination.perPage}
|
|
262
|
+
quantityLabel={totalItemsLabel}
|
|
263
|
+
setCurrentPage={pagination.setCurrentPage}
|
|
264
|
+
setItemsPerPage={pagination.setPerPage}
|
|
265
|
+
/>
|
|
266
|
+
)}
|
|
237
267
|
</div>
|
|
238
268
|
</div>
|
|
239
269
|
)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React, { useState, useEffect } from "react"
|
|
2
2
|
import { DragDropContext, Droppable, Draggable, DropResult } from "react-beautiful-dnd"
|
|
3
3
|
import { nanoid } from "nanoid"
|
|
4
|
+
import { faGripLines } from "@fortawesome/free-solid-svg-icons"
|
|
4
5
|
import { getTranslationWithArguments } from "../helpers/getTranslationWithArguments"
|
|
5
6
|
import { Icon, IconFillColors } from "../icons/Icon"
|
|
6
7
|
import { t } from "../helpers/translator"
|
|
7
|
-
import { faGripLines } from "@fortawesome/free-solid-svg-icons"
|
|
8
8
|
|
|
9
9
|
export interface TableHeadersOptions {
|
|
10
10
|
name: string
|
|
@@ -51,6 +51,8 @@ export type StandardTableCell = {
|
|
|
51
51
|
content: React.ReactNode
|
|
52
52
|
/** Text content that will replace this cell's header on mobile views */
|
|
53
53
|
mobileReplacement?: string
|
|
54
|
+
/** Classname to apply to this row */
|
|
55
|
+
rowClass?: string
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
export type StandardTableData = Record<string, StandardTableCell>[]
|
|
@@ -74,6 +76,10 @@ export interface StandardTableProps {
|
|
|
74
76
|
translateData?: boolean
|
|
75
77
|
/** An id applied to the table */
|
|
76
78
|
id?: string
|
|
79
|
+
strings?: {
|
|
80
|
+
orderString?: string
|
|
81
|
+
sortString?: string
|
|
82
|
+
}
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
const headerName = (header: string | TableHeadersOptions) => {
|
|
@@ -110,12 +116,16 @@ export const StandardTable = (props: StandardTableProps) => {
|
|
|
110
116
|
}, [props.data])
|
|
111
117
|
|
|
112
118
|
if (props.draggable) {
|
|
113
|
-
headerLabels.splice(0, 0, <th key={"header-draggable"}>{t("t.order")}</th>)
|
|
114
119
|
headerLabels.splice(
|
|
115
120
|
0,
|
|
116
121
|
0,
|
|
117
|
-
<th key={"header-draggable"}
|
|
118
|
-
|
|
122
|
+
<th key={"header-draggable-order"}>{props.strings?.orderString ?? t("t.order")}</th>
|
|
123
|
+
)
|
|
124
|
+
headerLabels.splice(
|
|
125
|
+
0,
|
|
126
|
+
0,
|
|
127
|
+
<th key={"header-draggable-sort"} className={"table__draggable-cell pl-5"}>
|
|
128
|
+
{props.strings?.sortString ?? t("t.sort")}
|
|
119
129
|
</th>
|
|
120
130
|
)
|
|
121
131
|
}
|
|
@@ -127,9 +137,11 @@ export const StandardTable = (props: StandardTableProps) => {
|
|
|
127
137
|
? `standardrow-${dataIndex}`
|
|
128
138
|
: nanoid()
|
|
129
139
|
|
|
140
|
+
let rowClass: string | undefined = ""
|
|
130
141
|
const cols = Object.keys(headers)?.map((colKey, colIndex) => {
|
|
131
142
|
const uniqKey = process.env.NODE_ENV === "test" ? `standardcol-${colIndex}` : nanoid()
|
|
132
143
|
const cell = row[colKey]?.content
|
|
144
|
+
rowClass = row[colKey]?.rowClass ? row[colKey].rowClass : ""
|
|
133
145
|
|
|
134
146
|
const cellClass = [headerClassName(headers[colKey]), cellClassName].join(" ")
|
|
135
147
|
|
|
@@ -156,7 +168,7 @@ export const StandardTable = (props: StandardTableProps) => {
|
|
|
156
168
|
0,
|
|
157
169
|
<Cell
|
|
158
170
|
key={`${dataIndex}-order-draggable`}
|
|
159
|
-
headerLabel={t("t.sort")}
|
|
171
|
+
headerLabel={props.strings?.sortString ?? t("t.sort")}
|
|
160
172
|
className={`pl-5 ${cellClassName ?? undefined}`}
|
|
161
173
|
>
|
|
162
174
|
{dataIndex + 1}
|
|
@@ -167,7 +179,7 @@ export const StandardTable = (props: StandardTableProps) => {
|
|
|
167
179
|
0,
|
|
168
180
|
<Cell
|
|
169
181
|
key={`${dataIndex}-sort-draggable`}
|
|
170
|
-
headerLabel={t("t.sort")}
|
|
182
|
+
headerLabel={props.strings?.sortString ?? t("t.sort")}
|
|
171
183
|
className={`table__draggable-cell pl-7`}
|
|
172
184
|
>
|
|
173
185
|
<Icon symbol={faGripLines} size={"medium"} fill={IconFillColors.primary} />
|
|
@@ -193,7 +205,7 @@ export const StandardTable = (props: StandardTableProps) => {
|
|
|
193
205
|
)}
|
|
194
206
|
</Draggable>
|
|
195
207
|
) : (
|
|
196
|
-
<tr id={rowKey} key={rowKey}>
|
|
208
|
+
<tr id={rowKey} key={rowKey} className={rowClass ? rowClass : ""}>
|
|
197
209
|
{cols}
|
|
198
210
|
</tr>
|
|
199
211
|
)}
|
package/src/text/Tag.scss
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
--pill-font-weight: 600;
|
|
12
12
|
--pill-text-transform: uppercase;
|
|
13
13
|
--pill-letter-spacing: var(--bloom-letter-spacing-ultrawide);
|
|
14
|
+
--pill-capitalized-text-transform: capitalized;
|
|
15
|
+
--pill-capitalized-letter-spacing: var(--bloom-letter-spacing-wide);
|
|
14
16
|
|
|
15
17
|
--small-pill-padding: var(--bloom-s1) var(--bloom-s3);
|
|
16
18
|
--small-pill-font-size: var(--bloom-font-size-2xs);
|
|
@@ -129,4 +131,9 @@
|
|
|
129
131
|
padding-block: var(--bloom-s2);
|
|
130
132
|
padding-inline: var(--bloom-s4);
|
|
131
133
|
}
|
|
134
|
+
|
|
135
|
+
&.is-capitalized {
|
|
136
|
+
text-transform: var(--pill-capitalized-text-transform);
|
|
137
|
+
letter-spacing: var(--pill-capitalized-letter-spacing);
|
|
138
|
+
}
|
|
132
139
|
}
|
package/src/text/Tag.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import "./Tag.scss"
|
|
|
5
5
|
export interface TagProps extends AppearanceProps {
|
|
6
6
|
className?: string
|
|
7
7
|
pillStyle?: boolean
|
|
8
|
+
capitalized?: boolean
|
|
8
9
|
children: React.ReactNode
|
|
9
10
|
fillContainer?: boolean
|
|
10
11
|
}
|
|
@@ -14,6 +15,7 @@ export const Tag = (props: TagProps) => {
|
|
|
14
15
|
|
|
15
16
|
if (props.pillStyle) tagClasses.push("is-pill")
|
|
16
17
|
if (props.fillContainer) tagClasses.push("fill-container")
|
|
18
|
+
if (props.capitalized) tagClasses.push("is-capitalized")
|
|
17
19
|
if (props.className) tagClasses.push(props.className)
|
|
18
20
|
|
|
19
21
|
return <span className={tagClasses.join(" ")}>{props.children}</span>
|