143 | ${languages.map((language) => {
144 | return html`
this.changeCurrentLanguage(language)}
147 | >
148 | ${language?.toUpperCase().replace('-', '\n')}
149 |
`;
150 | })}
151 |
152 | `;
153 | }
154 | }
155 |
156 | export default LanguageSelector;
157 |
--------------------------------------------------------------------------------
/src/components/Lazy.js:
--------------------------------------------------------------------------------
1 | import { Component, h } from 'preact';
2 |
3 | export class Lazy extends Component {
4 | async componentWillMount() {
5 | const module = await this.props.component();
6 | const Component = module.default || module;
7 | this.setState({ Component });
8 | }
9 |
10 | render({ props }, { Component }) {
11 | return h(Component, props);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/Tabs.js:
--------------------------------------------------------------------------------
1 | import { html } from 'htm/preact';
2 | import { Component } from 'preact';
3 | import { info, settings, refresh, add } from '../assets/icons/icons.js';
4 | import { addPwaUpdateListener } from '../utils/addPwaUpdateListener.js';
5 | import { installMediaQueryWatcher } from 'pwa-helpers/media-query.js';
6 | import { dialogService } from '../services/dialogService.js';
7 |
8 | const ICONS = {
9 | info,
10 | settings,
11 | updates: refresh,
12 | contribute: add,
13 | };
14 | const KEYCODE_LEFT = 37;
15 | const KEYCODE_RIGHT = 39;
16 |
17 | export default class Tabs extends Component {
18 | constructor() {
19 | super();
20 | this.state = {
21 | updateAvailable: false,
22 | index: 0,
23 | };
24 |
25 | this.tabRefs = {};
26 |
27 | this.__onFocusMove = this.__onFocusMove.bind(this);
28 | this.__onTabClick = this.__onTabClick.bind(this);
29 | }
30 |
31 | componentDidMount() {
32 | installMediaQueryWatcher(`(min-width: 960px)`, (matches) => {
33 | this.setState({ isMobile: !matches });
34 | });
35 |
36 | dialogService.addEventListener('close', (e) => {
37 | if (e.detail.menuDialogClosed) {
38 | this.tabRefs[`tab${this.state.index}`].focus();
39 | }
40 | });
41 |
42 | addPwaUpdateListener((updateAvailable) => {
43 | this.setState({
44 | updateAvailable,
45 | });
46 | });
47 | }
48 |
49 | updateIndex(i, type) {
50 | if (type === 'settings' && this.state.updateAvailable) {
51 | this.setState({
52 | updateAvailable: false,
53 | });
54 | }
55 |
56 | this.setState({ index: i });
57 | this.tabRefs[`tab${i}`].focus();
58 | if (!this.state.isMobile) {
59 | this.commit(type);
60 | }
61 | }
62 |
63 | __onTabClick(i, type) {
64 | this.updateIndex(i, type);
65 | this.commit(type);
66 | }
67 |
68 | commit(type) {
69 | this.props.switchContent(type.toLowerCase());
70 | }
71 |
72 | __onFocusMove(e) {
73 | const currIndex = this.state.index;
74 |
75 | switch (e.keyCode) {
76 | case KEYCODE_LEFT:
77 | if (currIndex !== 0) {
78 | this.updateIndex(currIndex - 1, this.tabRefs[`tab${currIndex - 1}`].getAttribute('data-label').toLowerCase());
79 | }
80 | break;
81 | case KEYCODE_RIGHT:
82 | if (currIndex !== this.props.children.length - 1) {
83 | this.updateIndex(currIndex + 1, this.tabRefs[`tab${currIndex + 1}`].getAttribute('data-label').toLowerCase());
84 | }
85 | break;
86 | }
87 | }
88 |
89 | render(_, { index }) {
90 | return html`
91 |
113 | `;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/components/TerritoryTabs.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Code-for-All/lockdown/7f2f3f61130f541537b89b150be49feeb5587dfa/src/components/TerritoryTabs.js
--------------------------------------------------------------------------------
/src/components/Totals.js:
--------------------------------------------------------------------------------
1 | import { html } from 'htm/preact';
2 | import { installMediaQueryWatcher } from 'pwa-helpers/media-query.js';
3 | import css from 'csz';
4 | import { Component } from 'preact';
5 | import { totalsService } from '../services/totalsService.js';
6 | import { format } from 'date-fns/esm';
7 |
8 | // ? Wrappers
9 | import withMobileDetection from './Wrappers/withMobileDetection';
10 |
11 | const styles = css`
12 | dl {
13 | display: flex;
14 | height: 100%;
15 | padding: 0;
16 | margin: 0;
17 | text-align: center;
18 | text-transform: uppercase;
19 | width:400px;
20 | @media (max-width: 590px) {
21 | width:100%;
22 | }
23 | }
24 |
25 | dl div {
26 | position: relative;
27 | display: flex;
28 | flex-direction: column;
29 | justify-content: space-between;
30 | width: 50%;
31 | @media (max-width: 899px) {
32 | width: 50%;
33 | }
34 | padding: 5px 16px;
35 | @media (max-width: 590px) {
36 | padding: 2px 6px;
37 | }
38 | margin: 5px 0;
39 | }
40 |
41 | dt {
42 | display: block;
43 | }
44 |
45 | dd {
46 | margin-left: 0px;
47 | display: block;
48 | margin-top:5px;
49 | }
50 |
51 | div:not(:last-of-type)::after {
52 | content: '';
53 | position: absolute;
54 | top: 0;
55 | bottom: 0;
56 | right: 0;
57 | width: 1px;
58 | background-color: #e0e0e0;
59 | }
60 | `;
61 |
62 | const SHOW_STATS = true;
63 |
64 | class Totals extends Component {
65 | constructor() {
66 | super();
67 |
68 | this.state = { totals: {} };
69 | }
70 |
71 | async componentDidUpdate(prevProps) {
72 | if (this.props.selectedDate !== prevProps.selectedDate) {
73 | const { startDate, endDate, selectedDate, daysRange } = this.props;
74 | this.setState({
75 | totals: await totalsService.getTotals({ date: selectedDate, startDate, endDate, daysRange }),
76 | });
77 | }
78 | }
79 |
80 | async componentDidMount() {
81 | installMediaQueryWatcher(`(min-width: 900px)`, (matches) => {
82 | this.setState({ desktop: matches });
83 | });
84 | const { daysRange } = this.props;
85 | const totals = await totalsService.getTotals({
86 | date: this.props.selectedDate,
87 | startDate: this.props.startDate,
88 | endDate: this.props.endDate,
89 | daysRange,
90 | });
91 |
92 | this.setState({
93 | totals: totals,
94 | });
95 | }
96 |
97 | // {
98 | // description: i18n.t('header.totals.cases'),
99 | // value: Number(totals.corona?.confirmed || 0).toLocaleString(),
100 | // },
101 | // {
102 | // description: i18n.t('header.totals.deaths'),
103 | // value: Number(totals.corona?.deaths || 0).toLocaleString(),
104 | // },
105 |
106 | render({ selectedDate, i18n }, { totals, desktop }) {
107 | const items = [
108 | {
109 | description: i18n.t('header.totals.territoriesLockdown'),
110 | value: Number(totals.territories?.lockdown || 0).toLocaleString(),
111 | },
112 | {
113 | description: i18n.t('header.totals.peopleAffected'),
114 | value: Number(totals.territories?.affected || 0).toLocaleString(),
115 | },
116 | ];
117 | return html`
118 |