Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
module.exports = {
'env': {
'browser': true,
'es2021': true,
jest: true,
},
'extends': [
'eslint:recommended',
'plugin:react/recommended',
'plugin:import/errors',
'plugin:import/typescript',
],
globals: {
Lang: 'readonly',
TSMLReactConfig: 'readonly',
Translation: 'readonly',
},
'overrides': [
{
'env': {
'node': true,
},
'files': ['.eslintrc.{js,cjs}'],
'parserOptions': {
'sourceType': 'script',
},
},
],
parser: '@typescript-eslint/parser',
'parserOptions': {
'ecmaVersion': 'latest',
'sourceType': 'module',
},
'plugins': ['react', 'import'],
'rules': {
'react/jsx-uses-react': 'off',
'react/no-unknown-property': ['error', { ignore: ['css'] }],

'no-unused-vars': [
'error',
{
'argsIgnorePattern': '^_',
'varsIgnorePattern': '^_',
'caughtErrorsIgnorePattern': '^_',
},
],

'react/react-in-jsx-scope': 'off',
'import/order': [
'error',
{
'groups': [
'builtin',
'external',
'internal',
'unknown',
'parent',
'sibling',
'index',
'object',
'type',
],
'pathGroups': [
{
pattern: 'react',
group: 'builtin',
position: 'before',
},
{
pattern: '@/**',
group: 'external',
position: 'after',
},
],
'pathGroupsExcludedImportTypes': ['builtin'],
'newlines-between': 'always',
'alphabetize': {
order: 'asc',
caseInsensitive: true,
},
},
],
},
settings: {
'import/resolver': {
typescript: {
project: './tsconfig.json',
},
},
},
};
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,22 @@
"@types/react-dom": "^18.2.4",
"@types/react-infinite-scroller": "^1.2.3",
"@types/react-test-renderer": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^6.19.0",
"@typescript-eslint/parser": "^6.19.0",
"eslint": "^8.56.0",
"eslint-config-standard-with-typescript": "^43.0.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.33.2",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.6.1",
"laravel-mix": "^6.0.49",
"react-test-renderer": "^18.2.0",
"serve": "^14.2.0",
"ts-loader": "^9.4.3",
"typescript": "^5.0.4"
"typescript": "^5.3.3"
},
"dependencies": {
"@code4recovery/spec": "^1.0.5",
Expand Down
4 changes: 2 additions & 2 deletions public/app.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions public/app.js.LICENSE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
*/

/**
* @remix-run/router v1.11.0
* @remix-run/router v1.14.2
*
* Copyright (c) Remix Software Inc.
*
Expand All @@ -58,7 +58,7 @@
*/

/**
* React Router DOM v6.18.0
* React Router DOM v6.21.3
*
* Copyright (c) Remix Software Inc.
*
Expand All @@ -69,7 +69,7 @@
*/

/**
* React Router v6.18.0
* React Router v6.21.3
*
* Copyright (c) Remix Software Inc.
*
Expand Down
6 changes: 4 additions & 2 deletions src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { createRoot } from 'react-dom/client';
import { TsmlUI } from './components';
import {
RouteObject,
RouterProvider,
createBrowserRouter,
} from 'react-router-dom';

import { TsmlUI } from './components';

// locate element
const element = document.getElementById('tsml-ui');

Expand All @@ -23,7 +24,8 @@ if (element) {
settings={
typeof tsml_react_config === 'undefined'
? undefined
: tsml_react_config
: // eslint-disable-next-line no-undef
tsml_react_config
}
src={element.getAttribute('data-src') || undefined}
timezone={element.getAttribute('data-timezone') || undefined}
Expand Down
13 changes: 6 additions & 7 deletions src/components/Alert.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import type { State } from '../types';
import Button from './Button';
import { useSearchParams } from 'react-router-dom';

import { formatString as i18n, getIndexByKey, useSettings } from '../helpers';
import { alertCss, errorCss } from '../styles';
import { useSearchParams } from 'react-router-dom';

type AlertProps = {
state: State;
};
import Button from './Button';

import type { State } from '../types';

export default function Alert({ state }: AlertProps) {
export default function Alert({ state }: { state: State }) {
const [searchParams, setSearchParams] = useSearchParams();
const { settings, strings } = useSettings();
return state.error ? (
Expand Down
17 changes: 8 additions & 9 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { buttonCss, buttonDirectionsCss, buttonJoinCss } from '../styles';
import Icon, { icons } from './Icon';

type ButtonProps = {
href?: string;
icon?: keyof typeof icons;
onClick?: () => void;
text?: string;
type?: 'in-person' | 'online';
};
import Icon, { icons } from './Icon';

export default function Button({
href,
icon,
onClick,
text,
type,
}: ButtonProps) {
}: {
href?: string;
icon?: keyof typeof icons;
onClick?: () => void;
text?: string;
type?: 'in-person' | 'online';
}) {
const Tag = href ? 'a' : 'button';
return (
<Tag
Expand Down
49 changes: 35 additions & 14 deletions src/components/Controls.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { useEffect, useRef, useState } from 'react';
import {
Dispatch,
SetStateAction,
FormEvent,
useEffect,
useRef,
useState,
MouseEvent,
} from 'react';

import { useSearchParams } from 'react-router-dom';

import { analyticsEvent, useSettings } from '../helpers';
import {
controlsCss,
Expand All @@ -13,17 +22,21 @@ import {
dropdownButtonLastCss,
dropdownCss,
} from '../styles';
import type { State } from '../types';

import Dropdown from './Dropdown';
import Icon from './Icon';

type ControlsProps = {
import type { State } from '../types';

export default function Controls({
state,
setState,
mapbox,
}: {
state: State;
setState: React.Dispatch<React.SetStateAction<State>>;
setState: Dispatch<SetStateAction<State>>;
mapbox?: string;
};

export default function Controls({ state, setState, mapbox }: ControlsProps) {
}) {
const { settings, strings } = useSettings();
const [dropdown, setDropdown] = useState<string>();
const [search, setSearch] = useState(
Expand Down Expand Up @@ -98,12 +111,12 @@ export default function Controls({ state, setState, mapbox }: ControlsProps) {
}, [searchInput.current?.value]);

//close current dropdown (on body click)
const closeDropdown = (e: MouseEvent) => {
const closeDropdown = () => {
setDropdown(undefined);
};

//near location search
const locationSearch = (e: React.FormEvent<HTMLFormElement>) => {
const locationSearch = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();

if (state.input.mode !== 'location') return;
Expand All @@ -120,7 +133,7 @@ export default function Controls({ state, setState, mapbox }: ControlsProps) {
};

//set search mode dropdown and clear all distances
const setMode = (e: React.MouseEvent, mode: 'search' | 'location' | 'me') => {
const setMode = (e: MouseEvent, mode: 'search' | 'location' | 'me') => {
e.preventDefault();

Object.keys(state.meetings).forEach(slug => {
Expand Down Expand Up @@ -162,10 +175,18 @@ export default function Controls({ state, setState, mapbox }: ControlsProps) {
};

//toggle list/map view
const setView = (e: React.MouseEvent, view: 'table' | 'map') => {
const setView = (e: MouseEvent, view: 'table' | 'map') => {
e.preventDefault();
state.input.view = view;
setState({ ...state });

if (view !== 'table') {
searchParams.set('view', view);
} else {
searchParams.delete('view');
}

setState({ ...state, input: { ...state.input, view } });

setSearchParams(searchParams);
};

return !Object.keys(state.meetings).length ? null : (
Expand All @@ -192,7 +213,7 @@ export default function Controls({ state, setState, mapbox }: ControlsProps) {
state.input.mode === 'location' ? search : state.input.search
}
/>
<input type="submit" hidden css={controlsInputSearchSubmitCss}/>
<input type="submit" hidden css={controlsInputSearchSubmitCss} />
{modes.length > 1 && (
<button
aria-label={strings.modes[state.input.mode]}
Expand Down
26 changes: 13 additions & 13 deletions src/components/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import { Fragment } from 'react';
import { Dispatch, Fragment, MouseEvent, SetStateAction } from 'react';

import { useSearchParams } from 'react-router-dom';

import { formatString as i18n, getIndexByKey, useSettings } from '../helpers';
import { dropdownButtonCss, dropdownCss } from '../styles';
import type { Index, State } from '../types';
import { useSearchParams } from 'react-router-dom';

type DropdownProps = {
defaultValue: string;
end: boolean;
filter: keyof State['indexes'];
open: boolean;
setDropdown: (dropdown?: string) => void;
state: State;
};
import type { Index, State } from '../types';

export default function Dropdown({
defaultValue,
Expand All @@ -21,15 +14,22 @@ export default function Dropdown({
open,
setDropdown,
state,
}: DropdownProps) {
}: {
defaultValue: string;
end: boolean;
filter: keyof State['indexes'];
open: boolean;
setDropdown: Dispatch<SetStateAction<string | undefined>>;
state: State;
}) {
const [searchParams, setSearchParams] = useSearchParams();
const { strings } = useSettings();
const options = state.indexes[filter];
const values = state.input[filter];

//set filter: pass it up to parent
const setFilter = (
e: React.MouseEvent<HTMLButtonElement>,
e: MouseEvent<HTMLButtonElement>,
filter: keyof typeof state.indexes,
value?: string
) => {
Expand Down
16 changes: 11 additions & 5 deletions src/components/Link.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { Dispatch, SetStateAction } from 'react';

import { NavLink } from 'react-router-dom';

import { formatUrl, useSettings } from '../helpers';

import type { State, Meeting } from '../types';

type LinkProps = {
export default function Link({
meeting,
setState,
state,
}: {
meeting: Meeting;
setState?: (state: State) => void;
setState?: Dispatch<SetStateAction<State>>;
state?: State;
};

export default function Link({ meeting, setState, state }: LinkProps) {
}) {
const { settings, strings } = useSettings();

const flags =
Expand Down
Loading