@bloom-housing/ui-components 4.4.0 → 4.4.1-alpha.10

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 CHANGED
@@ -3,6 +3,117 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [4.4.1-alpha.10](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.4.1-alpha.9...@bloom-housing/ui-components@4.4.1-alpha.10) (2022-06-01)
7
+
8
+
9
+ ### Features
10
+
11
+ * add accessibility building features to listing ([#2755](https://github.com/bloom-housing/bloom/issues/2755)) ([0c8dfb8](https://github.com/bloom-housing/bloom/commit/0c8dfb833d0ef6d4f4927636c9f01bae6f48e4f1))
12
+
13
+
14
+
15
+
16
+
17
+ ## [4.4.1-alpha.9](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.4.1-alpha.8...@bloom-housing/ui-components@4.4.1-alpha.9) (2022-05-31)
18
+
19
+
20
+ ### Features
21
+
22
+ * load overly to partner listings grid ([#2621](https://github.com/bloom-housing/bloom/issues/2621)) ([4785f34](https://github.com/bloom-housing/bloom/commit/4785f344831f97dac2164224e32247619e5ac808))
23
+
24
+
25
+
26
+
27
+
28
+ ## [4.4.1-alpha.8](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.4.1-alpha.7...@bloom-housing/ui-components@4.4.1-alpha.8) (2022-05-31)
29
+
30
+ **Note:** Version bump only for package @bloom-housing/ui-components
31
+
32
+
33
+
34
+
35
+
36
+ ## [4.4.1-alpha.7](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.4.1-alpha.6...@bloom-housing/ui-components@4.4.1-alpha.7) (2022-05-31)
37
+
38
+ **Note:** Version bump only for package @bloom-housing/ui-components
39
+
40
+
41
+
42
+
43
+
44
+ ## [4.4.1-alpha.6](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.4.1-alpha.5...@bloom-housing/ui-components@4.4.1-alpha.6) (2022-05-26)
45
+
46
+
47
+ ### Bug Fixes
48
+
49
+ * visual design bugs ([#2737](https://github.com/bloom-housing/bloom/issues/2737)) ([dbac685](https://github.com/bloom-housing/bloom/commit/dbac685cd1e4d276b57a1d961eb5707decbc248b))
50
+
51
+
52
+
53
+
54
+
55
+ ## [4.4.1-alpha.5](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.4.1-alpha.4...@bloom-housing/ui-components@4.4.1-alpha.5) (2022-05-26)
56
+
57
+ **Note:** Version bump only for package @bloom-housing/ui-components
58
+
59
+
60
+
61
+
62
+
63
+ ## [4.4.1-alpha.4](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.4.1-alpha.3...@bloom-housing/ui-components@4.4.1-alpha.4) (2022-05-26)
64
+
65
+ **Note:** Version bump only for package @bloom-housing/ui-components
66
+
67
+
68
+
69
+
70
+
71
+ ## [4.4.1-alpha.3](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.4.1-alpha.2...@bloom-housing/ui-components@4.4.1-alpha.3) (2022-05-25)
72
+
73
+ **Note:** Version bump only for package @bloom-housing/ui-components
74
+
75
+
76
+
77
+
78
+
79
+ ## [4.4.1-alpha.2](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.4.1-alpha.1...@bloom-housing/ui-components@4.4.1-alpha.2) (2022-05-25)
80
+
81
+ **Note:** Version bump only for package @bloom-housing/ui-components
82
+
83
+
84
+
85
+
86
+
87
+ ## [4.4.1-alpha.1](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.4.1-alpha.0...@bloom-housing/ui-components@4.4.1-alpha.1) (2022-05-25)
88
+
89
+ **Note:** Version bump only for package @bloom-housing/ui-components
90
+
91
+
92
+
93
+
94
+
95
+ ## [4.4.1-alpha.0](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.3.1-alpha.2...@bloom-housing/ui-components@4.4.1-alpha.0) (2022-05-25)
96
+
97
+
98
+ * 2022 05 24 sync master (#2754) ([f52781f](https://github.com/bloom-housing/bloom/commit/f52781fe18fbdad071d6e9a8a2b29877596c5492)), closes [#2754](https://github.com/bloom-housing/bloom/issues/2754) [#2753](https://github.com/bloom-housing/bloom/issues/2753) [#2441](https://github.com/bloom-housing/bloom/issues/2441) [#2460](https://github.com/bloom-housing/bloom/issues/2460) [#2459](https://github.com/bloom-housing/bloom/issues/2459) [#2464](https://github.com/bloom-housing/bloom/issues/2464) [#2465](https://github.com/bloom-housing/bloom/issues/2465) [#2466](https://github.com/bloom-housing/bloom/issues/2466) [#2436](https://github.com/bloom-housing/bloom/issues/2436) [#2451](https://github.com/bloom-housing/bloom/issues/2451) [#2415](https://github.com/bloom-housing/bloom/issues/2415) [#2354](https://github.com/bloom-housing/bloom/issues/2354) [#2455](https://github.com/bloom-housing/bloom/issues/2455) [#2484](https://github.com/bloom-housing/bloom/issues/2484) [#2482](https://github.com/bloom-housing/bloom/issues/2482) [#2483](https://github.com/bloom-housing/bloom/issues/2483) [#2476](https://github.com/bloom-housing/bloom/issues/2476) [#2485](https://github.com/bloom-housing/bloom/issues/2485) [#2470](https://github.com/bloom-housing/bloom/issues/2470) [#2488](https://github.com/bloom-housing/bloom/issues/2488) [#2487](https://github.com/bloom-housing/bloom/issues/2487) [#2496](https://github.com/bloom-housing/bloom/issues/2496) [#2498](https://github.com/bloom-housing/bloom/issues/2498) [#2499](https://github.com/bloom-housing/bloom/issues/2499) [#2291](https://github.com/bloom-housing/bloom/issues/2291) [#2461](https://github.com/bloom-housing/bloom/issues/2461) [#2485](https://github.com/bloom-housing/bloom/issues/2485) [#2494](https://github.com/bloom-housing/bloom/issues/2494) [#2503](https://github.com/bloom-housing/bloom/issues/2503) [#2495](https://github.com/bloom-housing/bloom/issues/2495) [#2477](https://github.com/bloom-housing/bloom/issues/2477) [#2505](https://github.com/bloom-housing/bloom/issues/2505) [#2372](https://github.com/bloom-housing/bloom/issues/2372) [#2489](https://github.com/bloom-housing/bloom/issues/2489) [#2497](https://github.com/bloom-housing/bloom/issues/2497) [#2506](https://github.com/bloom-housing/bloom/issues/2506) [#2486](https://github.com/bloom-housing/bloom/issues/2486)
99
+
100
+
101
+ ### BREAKING CHANGES
102
+
103
+ * consolidated all event section components in one new component, uptake will require removing the deprecated components and uptaking EventSection
104
+
105
+ * chore(release): version
106
+
107
+ - @bloom-housing/backend-core@3.0.2-alpha.38
108
+ - @bloom-housing/shared-helpers@4.0.1-alpha.63
109
+ - @bloom-housing/partners@4.0.1-alpha.67
110
+ - @bloom-housing/public@4.0.1-alpha.66
111
+ - @bloom-housing/ui-components@4.0.1-alpha.62
112
+
113
+
114
+
115
+
116
+
6
117
  # [4.4.0](https://github.com/seanmalbert/bloom/compare/@bloom-housing/ui-components@4.2.3...@bloom-housing/ui-components@4.4.0) (2022-05-24)
7
118
 
8
119
 
package/index.ts CHANGED
@@ -43,7 +43,6 @@ export * from "./src/forms/TimeField"
43
43
  /* Global */
44
44
  export * from "./src/global/AppearanceTypes"
45
45
  export * from "./src/global/ApplicationStatusType"
46
- export * from "./src/global/vendor/AgPagination"
47
46
 
48
47
  /* Headers */
49
48
  export * from "./src/headers/Hero"
@@ -147,6 +146,8 @@ export * from "./src/tables/GroupedTable"
147
146
  export * from "./src/tables/MinimalTable"
148
147
  export * from "./src/tables/StackedTable"
149
148
  export * from "./src/tables/CategoryTable"
149
+ export * from "./src/tables/AgTable"
150
+ export * from "./src/tables/AgPagination"
150
151
 
151
152
  /* Text */
152
153
  export * from "./src/text/Description"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloom-housing/ui-components",
3
- "version": "4.4.0",
3
+ "version": "4.4.1-alpha.10",
4
4
  "author": "Sean Albert <sean.albert@exygy.com>",
5
5
  "description": "Shared user interface components for Bloom affordable housing system",
6
6
  "homepage": "https://github.com/bloom-housing/bloom/tree/master/shared/ui-components",
@@ -53,7 +53,6 @@
53
53
  "identity-obj-proxy": "^3.0.0",
54
54
  "jest": "^26.5.3",
55
55
  "mockdate": "^3.0.2",
56
- "node-sass": "^7.0.0",
57
56
  "postcss": "^8.3.6",
58
57
  "postcss-loader": "^4.3",
59
58
  "preact": "^10.5.14",
@@ -61,7 +60,7 @@
61
60
  "react-is": "^17.0.2",
62
61
  "react-test-renderer": "^17.0.2",
63
62
  "regenerator-runtime": "^0.13.7",
64
- "sass": "^1.32.1",
63
+ "sass": "1.52.1",
65
64
  "sass-loader": "^10.0.3",
66
65
  "style-loader": "^1.1.3",
67
66
  "ts-jest": "^26.4.1",
@@ -70,7 +69,7 @@
70
69
  "webpack": "^4.44.2"
71
70
  },
72
71
  "dependencies": {
73
- "@bloom-housing/backend-core": "^4.4.0",
72
+ "@bloom-housing/backend-core": "^4.4.1-alpha.8",
74
73
  "@mapbox/mapbox-sdk": "^0.13.0",
75
74
  "@types/body-scroll-lock": "^2.6.1",
76
75
  "@types/jwt-decode": "^2.2.1",
@@ -82,6 +81,8 @@
82
81
  "@types/react-dom": "^16.9.5",
83
82
  "@types/react-text-mask": "^5.4.6",
84
83
  "@types/react-transition-group": "^4.4.0",
84
+ "ag-grid-community": "^26.0.0",
85
+ "ag-grid-react": "^26.0.0",
85
86
  "axios": "0.21.2",
86
87
  "body-scroll-lock": "^3.1.5",
87
88
  "dayjs": "^1.10.7",
@@ -102,5 +103,5 @@
102
103
  "tailwindcss": "2.2.10",
103
104
  "typesafe-actions": "^5.1.0"
104
105
  },
105
- "gitHead": "fdee7be9a9b3808139fbf4b06422736a7e03c235"
106
+ "gitHead": "d7d5fcaf26ddfb276c132dc6c6d1f9a3df7e9baa"
106
107
  }
@@ -106,8 +106,10 @@
106
106
  }
107
107
 
108
108
  .form-card__header_group {
109
+ @apply flex justify-center items-center;
109
110
  @apply bg-primary;
110
111
  @apply p-4;
112
+ @apply h-16;
111
113
 
112
114
  @screen md {
113
115
  @apply rounded-t-lg;
@@ -2,19 +2,26 @@ import * as React from "react"
2
2
  import "./FormCard.scss"
3
3
 
4
4
  export interface FormCardProps {
5
- header?: string
5
+ header?: FormCardHeader
6
6
  children: React.ReactNode
7
7
  className?: string
8
8
  }
9
9
 
10
+ export interface FormCardHeader {
11
+ isVisible: boolean
12
+ title: string
13
+ }
14
+
10
15
  const FormCard = (props: FormCardProps) => {
11
16
  const classNames = props.className ? `${props.className} form-card` : "form-card"
12
- if (props.header) {
17
+ if (props.header?.isVisible) {
13
18
  return (
14
19
  <article className={classNames}>
15
20
  <div className="form-card__header">
16
21
  <header className="form-card__header_group">
17
- <h1 className="form-card__header_title">{props.header}</h1>
22
+ {props.header.title && (
23
+ <h1 className="form-card__header_title">{props.header.title}</h1>
24
+ )}
18
25
  </header>
19
26
 
20
27
  <div className="form-card__header_nav">{props.children}</div>
@@ -74,13 +74,16 @@ const Field = (props: FieldProps) => {
74
74
  if (props.caps) labelClasses.push("field-label--caps")
75
75
  if (props.primary) labelClasses.push("text-primary")
76
76
  if (props.readerOnly) labelClasses.push("sr-only")
77
+ if (props.type === "checkbox" || props.type === "radio") {
78
+ labelClasses.push("font-semibold")
79
+ }
77
80
 
78
81
  return (
79
82
  <label className={labelClasses.join(" ")} htmlFor={props.id || props.name}>
80
83
  {props.label}
81
84
  </label>
82
85
  )
83
- }, [props.caps, props.primary, props.readerOnly, props.id, props.name, props.label])
86
+ }, [props.caps, props.primary, props.readerOnly, props.type, props.id, props.name, props.label])
84
87
 
85
88
  const idOrName = props.id || props.name
86
89
 
@@ -94,7 +94,7 @@ const FieldGroup = ({
94
94
  <label
95
95
  htmlFor={item.id}
96
96
  className={`font-semibold ${fieldLabelClassName} ${
97
- item.disabled && "text-gray-600 cursor-default cursor-not-allowed"
97
+ item.disabled && "text-gray-600 cursor-not-allowed"
98
98
  }`}
99
99
  >
100
100
  {item.label}
@@ -46,9 +46,7 @@ details.disclosure {
46
46
  .listing-detail-panel {
47
47
  @screen md {
48
48
  @apply ml-16;
49
- @apply p-8;
50
- @apply pt-0;
51
- @apply pl-0;
49
+ @apply pb-8;
52
50
  }
53
51
  }
54
52
 
@@ -1,9 +1,12 @@
1
1
  import * as React from "react"
2
2
  import { t } from "./translator"
3
- import { UnitSummary } from "@bloom-housing/backend-core/types"
3
+ import { UnitSummary, ListingAvailability } from "@bloom-housing/backend-core/types"
4
4
  import { StandardTableData } from "../tables/StandardTable"
5
5
 
6
- export const unitSummariesTable = (summaries: UnitSummary[]): StandardTableData => {
6
+ export const unitSummariesTable = (
7
+ summaries: UnitSummary[],
8
+ listingAvailability: ListingAvailability
9
+ ): StandardTableData => {
7
10
  const unitSummaries = summaries?.map((unitSummary) => {
8
11
  const unitPluralization = unitSummary.totalAvailable == 1 ? t("t.unit") : t("t.units")
9
12
  const minIncome =
@@ -43,6 +46,29 @@ export const unitSummariesTable = (summaries: UnitSummary[]): StandardTableData
43
46
  )
44
47
  : getRent(unitSummary.rentRange.min, unitSummary.rentRange.max)
45
48
 
49
+ let availability = null
50
+ if (listingAvailability === ListingAvailability.availableUnits) {
51
+ availability = (
52
+ <span>
53
+ {unitSummary.totalAvailable > 0 ? (
54
+ <>
55
+ <strong>{unitSummary.totalAvailable}</strong> {unitPluralization}
56
+ </>
57
+ ) : (
58
+ <span>
59
+ <strong>{t("listings.waitlist.open")}</strong>
60
+ </span>
61
+ )}
62
+ </span>
63
+ )
64
+ } else if (listingAvailability === ListingAvailability.openWaitlist) {
65
+ availability = (
66
+ <span>
67
+ <strong>{t("listings.waitlist.open")}</strong>
68
+ </span>
69
+ )
70
+ }
71
+
46
72
  return {
47
73
  unitType: {
48
74
  content: <strong>{t(`listings.unitTypes.${unitSummary.unitType?.name}`)}</strong>,
@@ -57,17 +83,7 @@ export const unitSummariesTable = (summaries: UnitSummary[]): StandardTableData
57
83
  },
58
84
  rent: { content: <span>{rent}</span> },
59
85
  availability: {
60
- content: (
61
- <span>
62
- {unitSummary.totalAvailable > 0 ? (
63
- <>
64
- <strong>{unitSummary.totalAvailable}</strong> {unitPluralization}
65
- </>
66
- ) : (
67
- <span className="uppercase">{t("listings.waitlist.label")}</span>
68
- )}
69
- </span>
70
- ),
86
+ content: availability,
71
87
  },
72
88
  }
73
89
  })
@@ -75,11 +91,14 @@ export const unitSummariesTable = (summaries: UnitSummary[]): StandardTableData
75
91
  return unitSummaries
76
92
  }
77
93
 
78
- export const getSummariesTable = (summaries: UnitSummary[]): StandardTableData => {
94
+ export const getSummariesTable = (
95
+ summaries: UnitSummary[],
96
+ listingAvailability: ListingAvailability
97
+ ): StandardTableData => {
79
98
  let unitSummaries: StandardTableData = []
80
99
 
81
100
  if (summaries?.length > 0) {
82
- unitSummaries = unitSummariesTable(summaries)
101
+ unitSummaries = unitSummariesTable(summaries, listingAvailability)
83
102
  }
84
103
  return unitSummaries
85
104
  }
@@ -394,6 +394,24 @@
394
394
  "authentication.timeout.signOutMessage": "Su seguridad es importante para nosotros. Concluimos su sesión debido a inactividad. Sírvase iniciar sesión para continuar.",
395
395
  "authentication.timeout.text": "Para proteger su identidad, su sesión concluirá en un minuto debido a inactividad. Si decide no responder, perderá toda la información que no haya guardado y concluirá su sesión.",
396
396
  "config.routePrefix": "es",
397
+ "eligibility.accessibility.acInUnit": "CA en la unidad",
398
+ "eligibility.accessibility.accessibleParking": "Estacionamiento Accesible",
399
+ "eligibility.accessibility.barrierFreeEntrance": "Entrada sin barreras",
400
+ "eligibility.accessibility.description": "Algunas propiedades tienen características de accesibilidad que otras pueden no tener.",
401
+ "eligibility.accessibility.elevator": "Ascensor",
402
+ "eligibility.accessibility.grabBars": "Barras de apoyo",
403
+ "eligibility.accessibility.hearing": "Audiencia",
404
+ "eligibility.accessibility.heatingInUnit": "Calefacción en Unidad",
405
+ "eligibility.accessibility.inUnitWasherDryer": "Lavadora y secadora en el apartamento",
406
+ "eligibility.accessibility.laundryInBuilding": "Lavandería en el edificio",
407
+ "eligibility.accessibility.mobility": "Movilidad",
408
+ "eligibility.accessibility.parkingOnSite": "Estacionamiento en el lugar",
409
+ "eligibility.accessibility.prompt": "¿Necesita funciones de accesibilidad adicionales?",
410
+ "eligibility.accessibility.rollInShower": "Rollo en la ducha",
411
+ "eligibility.accessibility.serviceAnimalsAllowed": "Se admiten animales de servicio",
412
+ "eligibility.accessibility.title": "Funciones de accesibilidad",
413
+ "eligibility.accessibility.visual": "Visual",
414
+ "eligibility.accessibility.wheelchairRamp": "Rampa para silla de ruedas",
397
415
  "errors.agreeError": "Debe estar de acuerdo con los términos para poder continuar",
398
416
  "errors.alert.badRequest": "¡Oops! Parece que algo salió mal. Por favor, inténtelo de nuevo. Comuníquese con su departamento de vivienda si sigue teniendo problemas.",
399
417
  "errors.alert.timeoutPleaseTryAgain": "¡Oops! Parece que algo salió mal. Por favor, inténtelo de nuevo.",
@@ -515,6 +515,24 @@
515
515
  "authentication.timeout.signOutMessage": "We care about your security. We logged you out due to inactivity. Please sign in to continue.",
516
516
  "authentication.timeout.text": "To protect your identity, your session will expire in one minute due to inactivity. You will lose any unsaved information and be logged out if you choose not to respond.",
517
517
  "config.routePrefix": "",
518
+ "eligibility.accessibility.acInUnit": "AC in Unit",
519
+ "eligibility.accessibility.accessibleParking": "Accessible Parking",
520
+ "eligibility.accessibility.barrierFreeEntrance": "Barrier Free Entrance",
521
+ "eligibility.accessibility.description": "Some properties have accessibility features that others may not have.",
522
+ "eligibility.accessibility.elevator": "Elevator",
523
+ "eligibility.accessibility.grabBars": "Grab Bars",
524
+ "eligibility.accessibility.hearing": "Hearing",
525
+ "eligibility.accessibility.heatingInUnit": "Heating in Unit",
526
+ "eligibility.accessibility.inUnitWasherDryer": "In Unit Washer Dryer",
527
+ "eligibility.accessibility.laundryInBuilding": "Laundry in Building",
528
+ "eligibility.accessibility.mobility": "Mobility",
529
+ "eligibility.accessibility.parkingOnSite": "Parking On Site",
530
+ "eligibility.accessibility.prompt": "Do you require additional accessibility features?",
531
+ "eligibility.accessibility.rollInShower": "Roll in Shower",
532
+ "eligibility.accessibility.serviceAnimalsAllowed": "Service Animals Allowed",
533
+ "eligibility.accessibility.title": "Accessibility Features",
534
+ "eligibility.accessibility.visual": "Visual",
535
+ "eligibility.accessibility.wheelchairRamp": "Wheelchair Ramp",
518
536
  "errors.agreeError": "You must agree to the terms in order to continue",
519
537
  "errors.alert.badRequest": "Looks like something went wrong. Please try again. \n\nContact your housing department if you're still experiencing issues.",
520
538
  "errors.alert.timeoutPleaseTryAgain": "Oops! Looks like something went wrong. Please try again.",
@@ -594,6 +612,7 @@
594
612
  "listings.availableAndWaitlist": "Available Units & Open Waitlist",
595
613
  "listings.availableUnitsAndWaitlist": "Available units and waitlist",
596
614
  "listings.availableUnitsAndWaitlistDesc": "Once applicants fill all available units, additional applicants will be placed on the waitlist for <span class='t-italic'>%{number} units</span>",
615
+ "listings.availableUnits": "Available Units",
597
616
  "listings.bath": "bath",
598
617
  "listings.browseListings": "Browse Listings",
599
618
  "listings.buildingImageAltText": "A picture of the building",
@@ -680,6 +699,7 @@
680
699
  "listings.sections.eligibilityTitle": "Eligibility",
681
700
  "listings.sections.featuresSubtitle": "Amenities, unit details and additional fees",
682
701
  "listings.sections.featuresTitle": "Features",
702
+ "listings.sections.accessibilityFeatures": "Accessibility Features",
683
703
  "listings.sections.housingPreferencesSubtitle": "Preference holders will be given highest ranking.",
684
704
  "listings.sections.housingPreferencesTitle": "Housing Preferences",
685
705
  "listings.sections.neighborhoodSubtitle": "Location and transportation",
@@ -809,6 +829,7 @@
809
829
  "states.WV": "West Virginia",
810
830
  "states.WY": "Wyoming",
811
831
  "t.accessibility": "Accessibility",
832
+ "t.additionalAccessibility": "Additional Accessibility",
812
833
  "t.additionalPhone": "Additional Phone",
813
834
  "t.am": "AM",
814
835
  "t.areYouStillWorking": "Are you still working?",
@@ -46,7 +46,7 @@
46
46
  display: flex;
47
47
  align-items: flex-start;
48
48
  flex-wrap: wrap;
49
- justify-content: end;
49
+ justify-content: flex-end;
50
50
  }
51
51
  }
52
52
  }
@@ -12,7 +12,7 @@ const LoadingOverlay = ({ isLoading, children }: LoadingOverlayProps) => {
12
12
  if (!isLoading) return children
13
13
 
14
14
  return (
15
- <div className="loading-overlay">
15
+ <div className="loading-overlay" data-test-id="loading-overlay">
16
16
  <Icon size="3xl" symbol="spinner" className="loading-overlay__spinner" />
17
17
  {children}
18
18
  </div>
@@ -15,7 +15,7 @@
15
15
  @apply w-full;
16
16
  @apply h-full;
17
17
  @apply bg-gray-900;
18
- @apply bg-opacity-50;
18
+ @apply opacity-50;
19
19
  transition-property: background-color;
20
20
 
21
21
  @include transition-timing;
@@ -37,7 +37,7 @@
37
37
  transform: translate(0px, 0px);
38
38
  }
39
39
  &.is-backdrop:before {
40
- @apply bg-opacity-50;
40
+ @apply opacity-50;
41
41
  }
42
42
  }
43
43
  }
@@ -13,7 +13,7 @@ type AgPaginationProps = {
13
13
  onPerPageChange?: (size: number) => void
14
14
  }
15
15
 
16
- const AG_PER_PAGE_OPTIONS = [8, 100, 500, 1000]
16
+ const AG_PER_PAGE_OPTIONS = [8, 25, 50, 100]
17
17
 
18
18
  const AgPagination = ({
19
19
  totalItems,
@@ -67,6 +67,7 @@ const AgPagination = ({
67
67
  {t("t.show")}
68
68
  </label>
69
69
  <select
70
+ data-test-id="ag-page-size"
70
71
  name="page-size"
71
72
  id="page-size"
72
73
  value={itemsPerPage}
@@ -85,6 +86,7 @@ const AgPagination = ({
85
86
  {t("t.jumpTo")}
86
87
  </label>
87
88
  <select
89
+ data-test-id="ag-page-select"
88
90
  name="page-jump"
89
91
  id="page-jump"
90
92
  onChange={(e: React.ChangeEvent<HTMLSelectElement>) =>
@@ -110,6 +112,7 @@ const AgPagination = ({
110
112
  <div className="w-full md:w-auto flex justify-between mt-5 md:mt-0 ">
111
113
  <div className="md:hidden">
112
114
  <Button
115
+ data-test-id="ag-btn-prev"
113
116
  className="data-pager__previous data-pager__control"
114
117
  onClick={onPrevClick}
115
118
  disabled={currentPage === 1}
@@ -119,6 +122,7 @@ const AgPagination = ({
119
122
  </div>
120
123
 
121
124
  <Button
125
+ data-test-id="ag-btn-next"
122
126
  className="data-pager__next data-pager__control"
123
127
  onClick={onNextClick}
124
128
  disabled={totalPages === currentPage || totalPages === 0}
@@ -0,0 +1,242 @@
1
+ import React, { useState, useCallback, useEffect, useRef } from "react"
2
+ import { useForm } from "react-hook-form"
3
+ import { AgGridReact } from "ag-grid-react"
4
+ import { GridOptions, ColumnState, ColumnApi, ColDef, ColGroupDef } from "ag-grid-community"
5
+ import { AgPagination, AG_PER_PAGE_OPTIONS } from "./AgPagination"
6
+ import { LoadingOverlay } from "../overlays/LoadingOverlay"
7
+ import { Field } from "../forms/Field"
8
+ import { AlertBox } from "../notifications/AlertBox"
9
+ import { debounce } from "../helpers/debounce"
10
+ import { t } from "../helpers/translator"
11
+
12
+ export interface ColumnOrder {
13
+ orderBy: string
14
+ orderDir: string
15
+ }
16
+
17
+ export interface AgTableProps {
18
+ id: string
19
+ config: AgTableConfig
20
+ data: AgTableData
21
+ pagination: AgTablePagination
22
+ search: AgTableSearch
23
+ sort?: AgTableSort
24
+ headerContent?: React.ReactNode
25
+ className?: string
26
+ }
27
+
28
+ export interface AgTablePagination {
29
+ perPage: number
30
+ setPerPage: React.Dispatch<React.SetStateAction<number>>
31
+ currentPage: number
32
+ setCurrentPage: React.Dispatch<React.SetStateAction<number>>
33
+ }
34
+
35
+ export interface AgTableConfig {
36
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
+ gridComponents?: { [p: string]: any }
38
+ columns: (ColDef | ColGroupDef)[]
39
+ totalItemsLabel: string
40
+ }
41
+
42
+ export interface AgTableData {
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ items: any[]
45
+ loading: boolean
46
+ totalItems: number
47
+ totalPages: number
48
+ }
49
+
50
+ export interface AgTableSearch {
51
+ setSearch: React.Dispatch<React.SetStateAction<string>>
52
+ }
53
+
54
+ export interface AgTableSort {
55
+ setSort?: React.Dispatch<React.SetStateAction<ColumnOrder[]>>
56
+ }
57
+
58
+ export const useAgTable = () => {
59
+ const [sortOptions, setSortOptions] = useState<ColumnOrder[]>([])
60
+ const [filterValue, setFilterValue] = useState("")
61
+
62
+ const [itemsPerPage, setItemsPerPage] = useState<number>(AG_PER_PAGE_OPTIONS[0])
63
+ const [currentPage, setCurrentPage] = useState<number>(1)
64
+
65
+ return {
66
+ filter: {
67
+ filterValue,
68
+ setFilterValue,
69
+ },
70
+ sort: {
71
+ sortOptions,
72
+ setSortOptions,
73
+ },
74
+ pagination: {
75
+ itemsPerPage,
76
+ setItemsPerPage,
77
+ currentPage,
78
+ setCurrentPage,
79
+ },
80
+ }
81
+ }
82
+
83
+ const AgTable = ({
84
+ id,
85
+ className,
86
+ pagination,
87
+ search: { setSearch },
88
+ sort: { setSort } = {},
89
+ headerContent,
90
+ data,
91
+ config: { gridComponents, columns, totalItemsLabel },
92
+ }: AgTableProps) => {
93
+ // local storage key with column state
94
+ const columnStateLsKey = `column-state_${id}`
95
+ const defaultColDef = {
96
+ resizable: true,
97
+ maxWidth: 300,
98
+ }
99
+
100
+ const [gridColumnApi, setGridColumnApi] = useState<ColumnApi | null>(null)
101
+
102
+ const [validSearch, setValidSearch] = useState<boolean>(true)
103
+
104
+ const gridOptions: GridOptions = {
105
+ onSortChanged: (params) => {
106
+ if (!setSort) return
107
+
108
+ saveColumnState(params.columnApi)
109
+ onSortChange(params.columnApi.getColumnState())
110
+ },
111
+ onColumnMoved: (params) => saveColumnState(params.columnApi),
112
+ components: gridComponents,
113
+ suppressNoRowsOverlay: data.loading,
114
+ }
115
+
116
+ // update table items order on sort change
117
+ const initialLoadOnSort = useRef<boolean>(false)
118
+
119
+ const onSortChange = useCallback(
120
+ (columns: ColumnState[]) => {
121
+ if (!setSort) return
122
+
123
+ // prevent multiple fetch on initial render
124
+ if (!initialLoadOnSort.current) {
125
+ initialLoadOnSort.current = true
126
+ return
127
+ }
128
+
129
+ const sortedColumns = columns.filter((col) => !!col.sort)
130
+
131
+ setSort(() =>
132
+ sortedColumns?.map((col) => ({
133
+ orderBy: col?.colId || "",
134
+ orderDir: col?.sort?.toUpperCase() || "",
135
+ }))
136
+ )
137
+ },
138
+ [setSort]
139
+ )
140
+
141
+ // eslint-disable-next-line @typescript-eslint/unbound-method
142
+ const { register, watch } = useForm()
143
+ const filterField = watch("filter-input", "")
144
+ const debounceFilter = useRef(
145
+ debounce((value: string) => {
146
+ setSearch(value)
147
+ pagination.setCurrentPage(1)
148
+ }, 500)
149
+ )
150
+ useEffect(() => {
151
+ if (filterField.length === 0 || filterField.length > 2) {
152
+ setValidSearch(true)
153
+ debounceFilter.current(filterField)
154
+ } else {
155
+ setSearch("")
156
+ setValidSearch(false)
157
+ }
158
+ }, [filterField, setSearch])
159
+
160
+ // Load a table state on initial render & pagination change (because the new data comes from the API)
161
+ useEffect(() => {
162
+ const savedColumnState = sessionStorage.getItem(columnStateLsKey)
163
+
164
+ if (gridColumnApi && savedColumnState) {
165
+ const parsedState: ColumnState[] = JSON.parse(savedColumnState)
166
+
167
+ gridColumnApi.applyColumnState({
168
+ state: parsedState,
169
+ applyOrder: true,
170
+ })
171
+ }
172
+ }, [gridColumnApi, id, columnStateLsKey])
173
+
174
+ const saveColumnState = (api: ColumnApi) => {
175
+ const columnState = api.getColumnState()
176
+ const columnStateJSON = JSON.stringify(columnState)
177
+ sessionStorage.setItem(columnStateLsKey, columnStateJSON)
178
+ }
179
+
180
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
181
+ const onGridReady = (params: any) => {
182
+ setGridColumnApi(params.columnApi)
183
+ }
184
+
185
+ return (
186
+ <div className={`ag-theme-alpine ag-theme-bloom ${className || ""}`}>
187
+ <div className="flex justify-between flex-col md:flex-row">
188
+ <div className="flex flex-wrap">
189
+ <div className="md:mr-5 w-full md:w-56">
190
+ <Field
191
+ dataTestId="ag-search-input"
192
+ name="filter-input"
193
+ label={t("t.filter")}
194
+ readerOnly={true}
195
+ register={register}
196
+ placeholder={t("t.filter")}
197
+ />
198
+ </div>
199
+ <div className="w-full md:w-auto mt-2 mb-2 md:mb-0">
200
+ {!validSearch && (
201
+ <AlertBox type="notice">{t("applications.table.searchError")}</AlertBox>
202
+ )}
203
+ </div>
204
+ </div>
205
+
206
+ {headerContent}
207
+ </div>
208
+
209
+ <div className="applications-table mt-5">
210
+ <LoadingOverlay isLoading={data.loading}>
211
+ <div>
212
+ <AgGridReact
213
+ defaultColDef={defaultColDef}
214
+ onGridReady={onGridReady}
215
+ gridOptions={gridOptions}
216
+ columnDefs={columns}
217
+ rowData={data.items}
218
+ domLayout={"autoHeight"}
219
+ headerHeight={83}
220
+ rowHeight={58}
221
+ suppressPaginationPanel={true}
222
+ paginationPageSize={AG_PER_PAGE_OPTIONS[0]}
223
+ suppressScrollOnNewData={true}
224
+ ></AgGridReact>
225
+ </div>
226
+ </LoadingOverlay>
227
+
228
+ <AgPagination
229
+ totalItems={data.totalItems}
230
+ totalPages={data.totalPages}
231
+ currentPage={pagination.currentPage}
232
+ itemsPerPage={pagination.perPage}
233
+ quantityLabel={totalItemsLabel}
234
+ setCurrentPage={pagination.setCurrentPage}
235
+ setItemsPerPage={pagination.setPerPage}
236
+ />
237
+ </div>
238
+ </div>
239
+ )
240
+ }
241
+
242
+ export { AgTable as default, AgTable }