Skip to content

Commit f31041a

Browse files
draft of support center page
1 parent cd77703 commit f31041a

File tree

3 files changed

+267
-0
lines changed

3 files changed

+267
-0
lines changed

src/Routes.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import About from "./About";
55
import Covid19 from "./Covid19";
66
import Hotlines from "./Hotlines";
77
import Info from "./Info";
8+
import Support from "./Support";
89

910
function Routes() {
1011
return (
@@ -27,6 +28,9 @@ function Routes() {
2728
<Route exact path="/en/info">
2829
<Info lang="en"/>
2930
</Route>
31+
<Route exact path="/en/support">
32+
<Support lang="en"/>
33+
</Route>
3034

3135
<Route exact path="/jp">
3236
<Covid19 lang="jp"/>
@@ -43,6 +47,9 @@ function Routes() {
4347
<Route exact path="/jp/info">
4448
<Info lang="jp"/>
4549
</Route>
50+
<Route exact path="/jp/support">
51+
<Support lang="jp"/>
52+
</Route>
4653

4754
<Route path="*">
4855
<Covid19 lang="en"/>

src/Support.css

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
.hotlines .title, .hotlines .date-updated {
2+
padding-left: 1.5rem;
3+
padding-right: 1.0rem;
4+
}
5+
6+
.card-header {
7+
cursor: pointer;
8+
}
9+
10+
.card-title {
11+
color: #005caf;
12+
margin-bottom: 0 !important;
13+
}
14+
15+
.area, .hotline {
16+
margin-left: 0;
17+
margin-right: 0;
18+
padding-left: 0;
19+
padding-right: 0;
20+
}
21+
22+
.area li {
23+
list-style-type: none;
24+
}
25+
26+
.center, .hotline {
27+
margin-bottom: 0.75rem;
28+
}
29+
30+
.center {
31+
margin-bottom: 1.5rem;
32+
}

src/Support.tsx

+228
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
import * as O from "fp-ts/lib/Option"
2+
import * as NEA from "fp-ts/lib/NonEmptyArray"
3+
import * as P from "fp-ts/lib/pipeable"
4+
import * as R from "rambda"
5+
import React from "react"
6+
import { Accordion, Card } from "react-bootstrap"
7+
import { StringUtils } from "turbocommons-ts"
8+
9+
import hotlines from "./data/support.json"
10+
import { Group, Hotline, groupByCenter, updateCenterNames } from "./hotline"
11+
import { tx as _tx } from "./translate"
12+
13+
import "./Support.css"
14+
15+
const makeId = (s: string): string =>
16+
StringUtils.formatCase(
17+
_tx('en')(s),
18+
StringUtils.FORMAT_LOWER_CAMEL_CASE
19+
)
20+
21+
const Hotlines = (props: {lang: string}): JSX.Element => {
22+
const tx = _tx(props.lang)
23+
24+
const makeContactA = (phone: string): JSX.Element =>
25+
phone.startsWith('http') ?
26+
<a href={phone} target="_blank" rel="noopener noreferrer">
27+
{phone}
28+
</a> :
29+
<a href={"tel:" + phone}>{phone}</a>
30+
31+
const makeContactsLi = (phones: Array<string>): JSX.Element => {
32+
const phoneAs: Array<JSX.Element> =
33+
phones.map(makeContactA)
34+
const commas: Array<string> =
35+
R.repeat(", ", phoneAs.length)
36+
const label: string =
37+
R.head(phones)?.startsWith('http') ?
38+
'Contact (VoIP)' :
39+
'Phone'
40+
const phonesBody =
41+
R.dropLast(1, R.flatten(R.zip(phoneAs, commas)))
42+
43+
return (
44+
<div className='phones'>
45+
<li>
46+
{tx(label)}: {phonesBody}
47+
</li>
48+
</div>
49+
)
50+
}
51+
52+
const makeHoursLi = (h: Hotline): JSX.Element => {
53+
const hours = h.hours.split('\n').map(tx)
54+
const hoursBody = hours.length > 1 ?
55+
<ul>{hours.map(x => <li>{x}</li>)}</ul> :
56+
hours
57+
return (
58+
<div className='hours-list'>
59+
<li>
60+
<div className='hours'>
61+
{tx('Hours of operation')}: {hoursBody}
62+
</div>
63+
</li>
64+
</div>
65+
)
66+
}
67+
68+
const makeLangLi = (h: Hotline): JSX.Element => {
69+
const supportedLangs: string =
70+
P.pipe(
71+
O.fromNullable(h.lang),
72+
O.getOrElse(() => 'Japanese')
73+
)
74+
75+
return (
76+
<li>
77+
<div className='lang'>
78+
{tx('Supported languages')}: {tx(supportedLangs)}
79+
</div>
80+
</li>
81+
)
82+
}
83+
84+
const makeCenterLi = (center: string, hotlines: Array<Hotline>) => {
85+
const url: string =
86+
P.pipe(
87+
R.head(hotlines),
88+
O.fromNullable,
89+
O.mapNullable((h: Hotline) => h.url),
90+
O.getOrElse(() => '')
91+
)
92+
93+
const centerElem: string | JSX.Element =
94+
url ?
95+
<a target="_blank" rel="noopener noreferrer"
96+
href={url}>{center}</a> :
97+
center
98+
99+
const grouped: Array<Array<Hotline>> =
100+
R.values(R.groupBy(h => `{h.hours}; {h.lang}`, hotlines))
101+
102+
if (R.head(hotlines)!.pref_ja === '鳥取県') {
103+
console.log("grouped:",
104+
grouped.map(hs => hs.map(h => [h.phone, h.hours, h.lang])))
105+
}
106+
107+
const body: Array<JSX.Element> =
108+
grouped.map((hs: Array<Hotline>) => {
109+
const phones = hs.map(h => h.phone)
110+
const head = R.head(hs)!
111+
return (
112+
<div className="hotline">
113+
{makeContactsLi(phones)}
114+
{makeHoursLi(head)}
115+
{makeLangLi(head)}
116+
</div>
117+
)
118+
})
119+
120+
return (
121+
<div className='center'>
122+
<h5>
123+
{centerElem}
124+
</h5>
125+
{body}
126+
</div>
127+
)
128+
}
129+
130+
const hotlines2Element = (
131+
area: Array<Hotline>,
132+
pref: string
133+
): JSX.Element => {
134+
const empty: Group<Hotline> = {}
135+
136+
const centers: Group<Hotline> =
137+
P.pipe(
138+
NEA.fromArray(area),
139+
O.map(groupByCenter),
140+
O.map(o => updateCenterNames(o)(props.lang)),
141+
O.getOrElse(() => empty)
142+
)
143+
144+
const lis =
145+
Object.entries(centers)
146+
.map(([k, v]) => makeCenterLi(k, v))
147+
148+
return (
149+
<div id={makeId(pref)} className="area">
150+
<ul>
151+
{lis}
152+
</ul>
153+
</div>
154+
)
155+
}
156+
157+
const makePrefToggle = (pref: string, area: Array<Hotline>) => (
158+
<Card>
159+
<Accordion.Toggle as={Card.Header} eventKey={"pref-" + makeId(pref)}>
160+
<Card.Title>
161+
{tx(pref)}
162+
</Card.Title>
163+
</Accordion.Toggle>
164+
<Accordion.Collapse eventKey={"pref-" + makeId(pref)}>
165+
<Card.Body>
166+
{hotlines2Element(area, pref)}
167+
</Card.Body>
168+
</Accordion.Collapse>
169+
</Card>
170+
)
171+
172+
const sortEnPrefs = (
173+
prefs: Record<string, Array<Hotline>>
174+
): Array<[string, Array<Hotline>]> => {
175+
const entries: Array<[string, Array<Hotline>]> = Object.entries(prefs)
176+
const tail: Array<[string, Array<Hotline>]> = R.tail(entries)
177+
return R.sortBy(
178+
([k, v]) => sortByPrefId(k, v),
179+
tail
180+
)
181+
}
182+
183+
const makeAccordionEn = () => {
184+
const sorted: Array<[string, Array<Hotline>]> =
185+
sortEnPrefs(hotlines.area)
186+
const toggles: Array<JSX.Element> =
187+
sorted.map(([k, v]) => makePrefToggle(k, v))
188+
189+
return (
190+
<Accordion>
191+
{toggles}
192+
</Accordion>
193+
)
194+
}
195+
196+
const sortByPrefId = (pref: string, area: Array<Hotline>) =>
197+
makeId(pref)
198+
199+
const makeAccordionJp = () => {
200+
const entries: Array<[string, Array<Hotline>]> =
201+
Object.entries(hotlines.area)
202+
const tail: Array<[string, Array<Hotline>]> =
203+
R.tail(entries)
204+
const toggles: Array<JSX.Element> =
205+
tail.map(([k, v]) => makePrefToggle(k, v))
206+
207+
return (
208+
<Accordion>
209+
{toggles}
210+
</Accordion>
211+
)
212+
}
213+
214+
215+
return (
216+
<div className="hotlines">
217+
<div className="title">
218+
<h3>{tx("Support Centers")}</h3>
219+
</div>
220+
<div className="date-updated">
221+
<p>{tx("Last updated")}: 2020/5/3</p>
222+
</div>
223+
{props.lang === 'en' ? makeAccordionEn(): makeAccordionJp()}
224+
</div>
225+
)
226+
}
227+
228+
export default Hotlines

0 commit comments

Comments
 (0)