1- import { useFlags } from "components/featureFlags"
2- import * as links from "components/links"
1+ import { doc , getDoc } from "firebase/firestore"
32import { useTranslation } from "next-i18next"
4- import { useState } from "react"
5- import styled from "styled-components"
6- import { Button , Col , Container , Modal , Row } from "../bootstrap"
3+ import { useCallback , useEffect , useState } from "react"
4+ import type { ModalProps } from "react-bootstrap"
5+ import styled , { ThemeConsumer } from "styled-components"
6+ import { useMediaQuery } from "usehooks-ts"
7+ import { Button , Col , Container , Image , Modal , Row , Stack } from "../bootstrap"
8+ import { useFlags } from "../featureFlags"
9+ import { firestore } from "../firebase"
10+ import * as links from "../links"
11+ import {
12+ ButtonContainer ,
13+ FeatureCalloutButton
14+ } from "../shared/CommonComponents"
715import { SmartDisclaimer } from "./SmartDisclaimer"
816import { SmartIcon } from "./SmartIcon"
917import { TestimonyCounts } from "./TestimonyCounts"
1018import { BillProps } from "./types"
11- import { currentGeneralCourt } from "functions/src/shared"
1219import { BillTopic } from "functions/src/bills/types"
13-
14- const SummaryContainer = styled ( Container ) `
15- background-color: white;
16- border-radius: 0.75rem;
17- padding: 1rem;
18- background-image: url("/quote-left.svg");
19- background-repeat: no-repeat;
20- background-size: 4rem;
21- background-position: 0.5rem 0.5rem;
22- `
23-
24- const TitleFormat = styled ( Col ) `
25- margin-top: 1rem;
26- font-style: italic;
27- font-size: 1.25rem;
28- `
20+ import { currentGeneralCourt } from "functions/src/shared"
2921
3022const Divider = styled ( Col ) `
3123 width: 2px;
@@ -34,23 +26,10 @@ const Divider = styled(Col)`
3426 align-self: stretch;
3527`
3628
37- const StyledButton = styled ( Button ) `
38- :focus {
39- box-shadow: none;
40- }
41- padding: 0;
42- margin: 0;
43- `
44-
4529const FormattedBillDetails = styled ( Col ) `
4630 white-space: pre-wrap;
4731`
4832
49- const SmartTagButton = styled . button `
50- border-radius: 12px;
51- font-size: 12px;
52- `
53-
5433const SmartTag = ( { topic } : { topic : BillTopic } ) => {
5534 return (
5635 < links . Internal
@@ -69,6 +48,55 @@ const SmartTag = ({ topic }: { topic: BillTopic }) => {
6948 )
7049}
7150
51+ const SmartTagButton = styled . button `
52+ border-radius: 12px;
53+ font-size: 12px;
54+ `
55+
56+ const StyledButton = styled ( Button ) `
57+ :focus {
58+ box-shadow: none;
59+ }
60+ padding: 0;
61+ margin: 0;
62+ `
63+
64+ const SummaryContainer = styled ( Container ) `
65+ background-color: white;
66+ border-radius: 0.75rem;
67+ padding: 1rem;
68+ background-image: url("/quote-left.svg");
69+ background-repeat: no-repeat;
70+ background-size: 4rem;
71+ background-position: 0.5rem 0.5rem;
72+ `
73+
74+ const TitleFormat = styled ( Col ) `
75+ margin-top: 1rem;
76+ font-style: italic;
77+ font-size: 1.25rem;
78+ `
79+
80+ export const ViewButton = styled . button `
81+ border-radius: 4px;
82+ border-width: 2px;
83+ height: fit-content;
84+ margin-top: 16px;
85+ width: fit-content;
86+
87+ @media (max-width: 425px) {
88+ margin-top: 32px;
89+ }
90+ `
91+
92+ export const ViewMessage = styled . div `
93+ width: 300px;
94+
95+ @media (max-width: 425px) {
96+ width: auto;
97+ }
98+ `
99+
72100export const Summary = ( {
73101 bill,
74102 className
@@ -77,10 +105,12 @@ export const Summary = ({
77105 const handleShowBillDetails = ( ) => setShowBillDetails ( true )
78106 const handleHideBillDetails = ( ) => setShowBillDetails ( false )
79107 const billText = bill ?. content ?. DocumentText
108+ const hearingIds = bill ?. hearingIds
80109
81110 const { showLLMFeatures } = useFlags ( )
82111
83112 const { t } = useTranslation ( "common" )
113+ const isMobile = useMediaQuery ( "(max-width: 991px)" )
84114
85115 return (
86116 < SummaryContainer className = { className } >
@@ -126,6 +156,45 @@ export const Summary = ({
126156 < Col className = { `d-flex` } xs = "auto" >
127157 < TestimonyCounts bill = { bill } />
128158 </ Col >
159+
160+ { hearingIds ? (
161+ < >
162+ { isMobile ? (
163+ < div >
164+ < hr className = { `m-0 border-bottom border-2` } />
165+ </ div >
166+ ) : (
167+ < Divider className = { `my-2` } xs = "auto" />
168+ ) }
169+
170+ < Col className = { `d-flex my-3` } xs = "auto" >
171+ < Stack >
172+ < Row className = { `d-flex flex-nowrap` } >
173+ < ButtonContainer className = { `mb-2 pe-1` } >
174+ < FeatureCalloutButton
175+ className = { `btn btn-secondary d-flex text-nowrap mt-1 mx-1 p-0` }
176+ >
177+ { t ( "new_feature" ) }
178+ </ FeatureCalloutButton >
179+ </ ButtonContainer >
180+ < div className = { `d-flex justify-content-start ps-0` } >
181+ { t ( "bill.hearing_video_and_transcript" , { ns : "common" } ) }
182+ </ div >
183+ </ Row >
184+ < ViewMessage >
185+ { t ( "view_the_hearing" , { ns : "common" } ) }
186+ </ ViewMessage >
187+ </ Stack >
188+ < Stack className = { `ms-3` } >
189+ < ButtonContainer className = { `d-flex align-self-center` } >
190+ < ViewChild bill = { bill } />
191+ </ ButtonContainer >
192+ </ Stack >
193+ </ Col >
194+ </ >
195+ ) : (
196+ < > </ >
197+ ) }
129198 </ Row >
130199 { showLLMFeatures ? (
131200 < >
@@ -150,3 +219,164 @@ export const Summary = ({
150219 </ SummaryContainer >
151220 )
152221}
222+
223+ const ViewChild = ( { bill } : BillProps ) => {
224+ const { t } = useTranslation ( "common" )
225+
226+ const hearingIds = bill . hearingIds
227+
228+ const [ hearingNums , setHearingNums ] = useState ( bill . hearingIds )
229+ const [ hearingsModal , setHearingsModal ] = useState < "show" | null > ( null )
230+
231+ const close = ( ) => setHearingsModal ( null )
232+
233+ const substringToRemove = "hearing-"
234+ const removeSubstring = ( ) => {
235+ const editedHearingIds = hearingIds ?. map ( str =>
236+ str . replace ( new RegExp ( substringToRemove , "g" ) , "" )
237+ )
238+ setHearingNums ( editedHearingIds )
239+ }
240+
241+ useEffect ( ( ) => {
242+ hearingIds ? removeSubstring ( ) : null
243+ } , [ ] )
244+
245+ return (
246+ < >
247+ { hearingIds ?. length === 1 ? (
248+ < links . Internal href = { `/hearing/${ hearingNums } ` } className = "" >
249+ < ViewButton className = { `btn btn-outline-secondary fw-bold p-1` } >
250+ { t ( "view" , { ns : "common" } ) }
251+ </ ViewButton >
252+ </ links . Internal >
253+ ) : (
254+ < ViewButton
255+ className = { `btn btn-outline-secondary fw-bold p-1` }
256+ onClick = { ( ) => setHearingsModal ( "show" ) }
257+ >
258+ { t ( "view" , { ns : "common" } ) }
259+ </ ViewButton >
260+ ) }
261+ < HearingsModal
262+ hearingNums = { hearingNums }
263+ onHide = { close }
264+ onHearingsModalClose = { ( ) => setHearingsModal ( null ) }
265+ show = { hearingsModal === "show" }
266+ />
267+ </ >
268+ )
269+ }
270+
271+ type Props = Pick < ModalProps , "show" | "onHide" > & {
272+ hearingNums : string [ ] | undefined
273+ onHearingsModalClose : ( ) => void
274+ }
275+
276+ function HearingsModal ( {
277+ hearingNums,
278+ onHide,
279+ onHearingsModalClose,
280+ show
281+ } : Props ) {
282+ const { t } = useTranslation ( [ "common" ] )
283+
284+ return (
285+ < Modal
286+ show = { show }
287+ onHide = { onHide }
288+ aria-labelledby = "hearings-modal"
289+ centered
290+ >
291+ < Modal . Header className = { `px-3 py-1` } >
292+ < Modal . Title id = "hearings-modal" >
293+ < b > { t ( "bill.select_hearing" , { ns : "common" } ) } </ b >
294+ </ Modal . Title >
295+ < Image
296+ src = "/x_cancel.png"
297+ alt = { t ( "navigation.closeNavMenu" , { ns : "editProfile" } ) }
298+ width = "25"
299+ height = "25"
300+ className = "ms-2"
301+ onClick = { onHearingsModalClose }
302+ />
303+ </ Modal . Header >
304+ < Modal . Body className = { `bg-white p-3` } >
305+ < hr className = { `m-0 border-bottom border-2` } />
306+ < p className = { `fw-bold fs-6` } >
307+ { t ( "bill.multiple_hearings" , { ns : "common" } ) }
308+ </ p >
309+ { hearingNums ?. map ( ( element : any , index : number ) => (
310+ < Hearing key = { index } hearingId = { element } />
311+ ) ) }
312+ </ Modal . Body >
313+ </ Modal >
314+ )
315+ }
316+
317+ const HearingRow = styled . div `
318+ &:nth-child(odd) {
319+ background-color: #eae7e7;
320+ &:nth-child(even) {
321+ background-color: white;
322+ }
323+ `
324+
325+ function Hearing ( { hearingId } : { hearingId : string } ) {
326+ const [ committeeCode , setCommitteeCode ] = useState ( "" )
327+ const [ committeeName , setCommitteeName ] = useState ( "" )
328+ const [ eventDate , setEventDate ] = useState ( "" )
329+ const [ generalCourtNumber , setGeneralCourtNumber ] = useState ( "" )
330+
331+ const hearingData = useCallback ( async ( ) => {
332+ const hearing = await getDoc ( doc ( firestore , `events/hearing-${ hearingId } ` ) )
333+ const docData = hearing . data ( )
334+
335+ setCommitteeCode ( docData ?. content . HearingHost . CommitteeCode )
336+ setCommitteeName ( docData ?. content . Name )
337+ setEventDate ( docData ?. content . EventDate )
338+ setGeneralCourtNumber ( docData ?. content . HearingHost . GeneralCourtNumber )
339+ } , [ hearingId ] )
340+
341+ useEffect ( ( ) => {
342+ hearingId ? hearingData ( ) : null
343+ } , [ ] )
344+
345+ const [ branch , setBranch ] = useState ( "" )
346+
347+ const committeeData = useCallback ( async ( ) => {
348+ const committee = await getDoc (
349+ doc (
350+ firestore ,
351+ `generalCourts/${ generalCourtNumber } /committees/${ committeeCode } `
352+ )
353+ )
354+ const docData = committee . data ( )
355+ setBranch ( docData ?. content ?. Branch )
356+ } , [ committeeCode , generalCourtNumber ] )
357+
358+ useEffect ( ( ) => {
359+ committeeCode && generalCourtNumber ? committeeData ( ) : null
360+ } , [ committeeCode , committeeData , generalCourtNumber ] )
361+
362+ const date = new Date ( eventDate )
363+ const month = ( date . getMonth ( ) + 1 ) . toString ( ) . padStart ( 2 , "0" )
364+ const day = date . getDate ( ) . toString ( ) . padStart ( 2 , "0" )
365+ const year = date . getFullYear ( )
366+
367+ return (
368+ < HearingRow className = { `d-flex justify-content-between w-auto` } >
369+ < Col xs = { 3 } className = { `mx-2` } >
370+ { `${ month } -${ day } -${ year } ` }
371+ </ Col >
372+ < Col xs = { 7 } className = { `me-2` } >
373+ < links . Internal href = { `/hearing/${ hearingId } ` } >
374+ { committeeName }
375+ </ links . Internal >
376+ </ Col >
377+ < Col xs = { 2 } className = { `` } >
378+ { branch }
379+ </ Col >
380+ </ HearingRow >
381+ )
382+ }
0 commit comments