diff --git a/README.md b/README.md index b69e72c3dd..6ff2b82e80 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Status | Feature - + ## Developers diff --git a/frontend/public/index.html b/frontend/index.html similarity index 90% rename from frontend/public/index.html rename to frontend/index.html index 8d5db278e6..2244390f6f 100644 --- a/frontend/public/index.html +++ b/frontend/index.html @@ -2,7 +2,7 @@ - + @@ -27,7 +27,7 @@ manifest.json provides metadata used when your web app is installed on a user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ --> - + %REACT_APP_ORG_CODE% Tasking Manager
+
.env; else cp .env.expand .env; fi\"", - "start": "npm run preparation && npm run copy-static && npm run patch-id && npm run patch-rapid && craco start", + "dev": "vite", + "start": "npm run preparation && npm run copy-static && npm run patch-id && npm run patch-rapid && vite start", "build": "npm run preparation && npm run update-static && npm run patch-id && npm run patch-rapid && craco build && npm run sentry:sourcemaps", "prettier": "prettier --write 'src/**/*.js'", "lint": "eslint src", @@ -117,6 +119,11 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.2.1", "@testing-library/user-event": "^14.4.3", + "@types/chart.js": "^2.9.41", + "@types/dompurify": "^3.0.5", + "@types/react-test-renderer": "^18.3.0", + "@types/slug": "^5.0.9", + "@vitejs/plugin-react-swc": "^3.7.0", "combine-react-intl-messages": "^4.0.0", "jest-canvas-mock": "^2.5.2", "msw": "^1.3.2", @@ -124,7 +131,8 @@ "react-scripts": "^5.0.1", "react-select-event": "^5.5.1", "react-test-renderer": "^18.2.0", - "source-map-explorer": "^2.5.3" + "source-map-explorer": "^2.5.3", + "vite": "^5.4.2" }, "resolutions": { "dom-accessibility-api": "0.5.14" diff --git a/frontend/src/App.js b/frontend/src/App.tsx similarity index 97% rename from frontend/src/App.js rename to frontend/src/App.tsx index b79667f555..03a029ade4 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.tsx @@ -38,7 +38,7 @@ const queryClient = new QueryClient({ }); const App = () => { - useMeta({ property: 'og:url', content: process.env.REACT_APP_BASE_URL }); + useMeta({ property: 'og:url', content: import.meta.env.REACT_APP_BASE_URL }); useMeta({ name: 'author', content: ORG_NAME }); const isLoading = useSelector((state) => state.loader.isLoading); const locale = useSelector((state) => state.preferences.locale); diff --git a/frontend/src/api/apiClient.js b/frontend/src/api/apiClient.ts similarity index 88% rename from frontend/src/api/apiClient.js rename to frontend/src/api/apiClient.ts index ebc860d0f9..f51b172c22 100644 --- a/frontend/src/api/apiClient.js +++ b/frontend/src/api/apiClient.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import { API_URL } from '../config'; -const api = (token, locale) => { +const api = (token?: string, locale?: string) => { const instance = axios.create({ baseURL: API_URL.toString(), headers: { diff --git a/frontend/src/api/notifications.js b/frontend/src/api/notifications.ts similarity index 69% rename from frontend/src/api/notifications.js rename to frontend/src/api/notifications.ts index 358e66dfc4..f2313dc0c7 100644 --- a/frontend/src/api/notifications.js +++ b/frontend/src/api/notifications.ts @@ -4,10 +4,11 @@ import { useQuery } from '@tanstack/react-query'; import { backendToQueryConversion } from '../hooks/UseInboxQueryAPI'; import { remapParamsToAPI } from '../utils/remapParamsToAPI'; import api from './apiClient'; +import { RootStore } from '../store'; -export const useNotificationsQuery = (inboxQuery) => { - const token = useSelector((state) => state.auth.token); - const fetchNotifications = async (signal, queryKey) => { +export const useNotificationsQuery = (inboxQuery: string) => { + const token = useSelector((state: RootStore) => state.auth.token); + const fetchNotifications = async (signal: AbortSignal, queryKey: string) => { const [, inboxQuery] = queryKey; const response = await api(token).get(`notifications/?${serializeParams(inboxQuery)}`, { signal, @@ -24,8 +25,8 @@ export const useNotificationsQuery = (inboxQuery) => { }; export const useUnreadNotificationsCountQuery = () => { - const token = useSelector((state) => state.auth.token); - const fetchUnreadNotificationCount = async (signal) => { + const token = useSelector((state: RootStore) => state.auth.token); + const fetchUnreadNotificationCount = async (signal: AbortSignal) => { const response = await api(token).get('notifications/queries/own/count-unread/', { signal, }); @@ -34,13 +35,15 @@ export const useUnreadNotificationsCountQuery = () => { return useQuery({ queryKey: ['notifications', 'unread-count'], - queryFn: ({ signal }) => fetchUnreadNotificationCount(signal), + queryFn: ({ signal }: { + signal: AbortSignal + }) => fetchUnreadNotificationCount(signal), refetchInterval: 1000 * 30, refetchOnWindowFocus: true, }); }; -function serializeParams(queryState) { +function serializeParams(queryState: unknown) { const obj = remapParamsToAPI(queryState, backendToQueryConversion); Object.keys(obj).forEach((key) => { diff --git a/frontend/src/api/organisations.js b/frontend/src/api/organisations.ts similarity index 62% rename from frontend/src/api/organisations.js rename to frontend/src/api/organisations.ts index ee539fc308..6a9d383b0f 100644 --- a/frontend/src/api/organisations.js +++ b/frontend/src/api/organisations.ts @@ -2,11 +2,14 @@ import { useQuery } from '@tanstack/react-query'; import { useSelector } from 'react-redux'; import api from './apiClient'; +import { RootStore } from '../store'; -export const useUserOrganisationsQuery = (userId) => { - const token = useSelector((state) => state.auth.token); +export const useUserOrganisationsQuery = (userId: string | number) => { + const token = useSelector((state: RootStore) => state.auth.token); - const fetchOrganisations = ({ signal }) => { + const fetchOrganisations = ({ signal }: { + signal: AbortSignal; + }) => { return api(token).get(`organisations/`, { signal, params: { diff --git a/frontend/src/api/projects.js b/frontend/src/api/projects.ts similarity index 64% rename from frontend/src/api/projects.js rename to frontend/src/api/projects.ts index 770067d272..537f402501 100644 --- a/frontend/src/api/projects.js +++ b/frontend/src/api/projects.ts @@ -1,17 +1,18 @@ import axios from 'axios'; import { subMonths, format } from 'date-fns'; -import { useQuery } from '@tanstack/react-query'; +import { QueryKey, QueryOptions, useQuery } from '@tanstack/react-query'; import { useSelector } from 'react-redux'; import { remapParamsToAPI } from '../utils/remapParamsToAPI'; import api from './apiClient'; import { UNDERPASS_URL } from '../config'; +import { RootStore } from '../store'; -export const useProjectsQuery = (fullProjectsQuery, action, queryOptions) => { - const token = useSelector((state) => state.auth.token); - const locale = useSelector((state) => state.preferences['locale']); +export const useProjectsQuery = (fullProjectsQuery: string, action: string, queryOptions: QueryOptions) => { + const token = useSelector((state: RootStore) => state.auth.token); + const locale = useSelector((state: RootStore) => state.preferences['locale']); - const fetchProjects = (signal, queryKey) => { + const fetchProjects = async (signal: AbortSignal | undefined, queryKey: QueryKey) => { const [, fullProjectsQuery, action] = queryKey; const paramsRemapped = remapParamsToAPI(fullProjectsQuery, backendToQueryConversion); // it's needed in order to query by action when the user goes to /explore page @@ -23,7 +24,7 @@ export const useProjectsQuery = (fullProjectsQuery, action, queryOptions) => { paramsRemapped.lastUpdatedTo = format(subMonths(Date.now(), 6), 'yyyy-MM-dd'); } - return api(token, locale) + return await api(token, locale) .get('projects/', { signal, params: paramsRemapped, @@ -39,10 +40,12 @@ export const useProjectsQuery = (fullProjectsQuery, action, queryOptions) => { }); }; -export const useProjectQuery = (projectId) => { - const token = useSelector((state) => state.auth.token); - const locale = useSelector((state) => state.preferences['locale']); - const fetchProject = ({ signal }) => { +export const useProjectQuery = (projectId: string) => { + const token = useSelector((state: RootStore) => state.auth.token); + const locale = useSelector((state: RootStore) => state.preferences['locale']); + const fetchProject = ({ signal }: { + signal: AbortSignal; + }) => { return api(token, locale).get(`projects/${projectId}/`, { signal, }); @@ -53,11 +56,13 @@ export const useProjectQuery = (projectId) => { queryFn: fetchProject, }); }; -export const useProjectSummaryQuery = (projectId, otherOptions = {}) => { - const token = useSelector((state) => state.auth.token); - const locale = useSelector((state) => state.preferences['locale']); +export const useProjectSummaryQuery = (projectId: string, otherOptions = {}) => { + const token = useSelector((state: RootStore) => state.auth.token); + const locale = useSelector((state: RootStore) => state.preferences['locale']); - const fetchProjectSummary = ({ signal }) => { + const fetchProjectSummary = ({ signal }: { + signal: AbortSignal; + }) => { return api(token, locale).get(`projects/${projectId}/queries/summary/`, { signal, }); @@ -71,8 +76,10 @@ export const useProjectSummaryQuery = (projectId, otherOptions = {}) => { }); }; -export const useProjectContributionsQuery = (projectId, otherOptions = {}) => { - const fetchProjectContributions = ({ signal }) => { +export const useProjectContributionsQuery = (projectId: string, otherOptions = {}) => { + const fetchProjectContributions = ({ signal }: { + signal: AbortSignal; + }) => { return api().get(`projects/${projectId}/contributions/`, { signal, }); @@ -86,9 +93,11 @@ export const useProjectContributionsQuery = (projectId, otherOptions = {}) => { }); }; -export const useActivitiesQuery = (projectId) => { +export const useActivitiesQuery = (projectId: string) => { const ACTIVITIES_REFETCH_INTERVAL = 1000 * 60; - const fetchProjectActivities = ({ signal }) => { + const fetchProjectActivities = ({ signal }: { + signal: AbortSignal; + }) => { return api().get(`projects/${projectId}/activities/latest/`, { signal, }); @@ -101,12 +110,14 @@ export const useActivitiesQuery = (projectId) => { refetchIntervalInBackground: false, refetchInterval: ACTIVITIES_REFETCH_INTERVAL, refetchOnWindowFocus: true, - useErrorBoundary: true, + throwOnError: true, }); }; -export const useTasksQuery = (projectId, otherOptions = {}) => { - const fetchProjectTasks = ({ signal }) => { +export const useTasksQuery = (projectId: string, otherOptions = {}) => { + const fetchProjectTasks = ({ signal }: { + signal: AbortSignal; + }) => { return api().get(`projects/${projectId}/tasks/`, { signal, }); @@ -120,8 +131,10 @@ export const useTasksQuery = (projectId, otherOptions = {}) => { }); }; -export const usePriorityAreasQuery = (projectId) => { - const fetchProjectPriorityArea = (signal) => { +export const usePriorityAreasQuery = (projectId: string) => { + const fetchProjectPriorityArea = (signal: { + signal: AbortSignal; + }) => { return api().get(`projects/${projectId}/queries/priority-areas/`, { signal, }); @@ -134,8 +147,10 @@ export const usePriorityAreasQuery = (projectId) => { }); }; -export const useProjectTimelineQuery = (projectId) => { - const fetchTimelineData = (signal) => { +export const useProjectTimelineQuery = (projectId: string) => { + const fetchTimelineData = (signal: { + signal: AbortSignal; + }) => { return api().get(`projects/${projectId}/contributions/queries/day/`, { signal, }); @@ -148,10 +163,12 @@ export const useProjectTimelineQuery = (projectId) => { }); }; -export const useTaskDetail = (projectId, taskId, shouldRefetch) => { - const token = useSelector((state) => state.auth.token); +export const useTaskDetail = (projectId: string, taskId: number, shouldRefetch: boolean) => { + const token = useSelector((state: RootStore) => state.auth.token); - const fetchTaskDetail = ({ signal }) => { + const fetchTaskDetail = ({ signal }: { + signal: AbortSignal; + }) => { return api(token).get(`projects/${projectId}/tasks/${taskId}/`, { signal, }); @@ -167,26 +184,26 @@ export const useTaskDetail = (projectId, taskId, shouldRefetch) => { }; // MAPPING -export const stopMapping = (projectId, taskId, comment, token, locale = 'en') => { +export const stopMapping = (projectId: string, taskId: number, comment: string, token: string, locale: string = 'en') => { return api(token, locale).post(`projects/${projectId}/tasks/actions/stop-mapping/${taskId}/`, { comment, }); }; -export const splitTask = (projectId, taskId, token, locale) => { +export const splitTask = (projectId: string, taskId: number, token: string, locale: string = 'en') => { return api(token, locale).post(`projects/${projectId}/tasks/actions/split/${taskId}/`); }; -export const submitMappingTask = (url, payload, token, locale) => { +export const submitMappingTask = (url: string, payload: any, token: string, locale: string = 'en') => { return api(token, locale).post(url, payload); }; // VALIDATION -export const stopValidation = (projectId, payload, token, locale = 'en') => { +export const stopValidation = (projectId: string, payload: any, token: string, locale: string = 'en') => { return api(token, locale).post(`projects/${projectId}/tasks/actions/stop-validation/`, payload); }; -export const submitValidationTask = (projectId, payload, token, locale) => { +export const submitValidationTask = (projectId: string, payload: any, token: string, locale: string = 'en') => { return api(token, locale).post( `projects/${projectId}/tasks/actions/unlock-after-validation/`, payload, @@ -205,7 +222,7 @@ export const useAvailableCountriesQuery = () => { }); }; -export const useAllPartnersQuery = (token, userId) => { +export const useAllPartnersQuery = (token: string, userId: string) => { const fetchAllPartners = () => { return api(token).get('partners/'); }; diff --git a/frontend/src/api/questionsAndComments.js b/frontend/src/api/questionsAndComments.ts similarity index 52% rename from frontend/src/api/questionsAndComments.js rename to frontend/src/api/questionsAndComments.ts index 4c907e7a12..c87b354456 100644 --- a/frontend/src/api/questionsAndComments.js +++ b/frontend/src/api/questionsAndComments.ts @@ -2,12 +2,15 @@ import { useQuery } from '@tanstack/react-query'; import { useSelector } from 'react-redux'; import api from './apiClient'; +import { RootStore } from '../store'; -export const useCommentsQuery = (projectId, page) => { - const token = useSelector((state) => state.auth.token); - const locale = useSelector((state) => state.preferences['locale']); +export const useCommentsQuery = (projectId: string, page: number) => { + const token = useSelector((state: RootStore) => state.auth.token); + const locale = useSelector((state: RootStore) => state.preferences['locale']); - const getComments = ({ signal }) => { + const getComments = ({ signal }: { + signal: AbortSignal; + }) => { return api(token, locale).get(`projects/${projectId}/comments/`, { signal, params: { @@ -24,11 +27,11 @@ export const useCommentsQuery = (projectId, page) => { }); }; -export const postProjectComment = (projectId, comment, token, locale = 'en') => { +export const postProjectComment = (projectId: string, comment: string, token: string, locale: string = 'en') => { return api(token, locale).post(`projects/${projectId}/comments/`, { message: comment }); }; -export const postTaskComment = (projectId, taskId, comment, token, locale = 'en') => { +export const postTaskComment = (projectId: string, taskId: number, comment: string, token: string, locale: string = 'en') => { return api(token, locale).post(`projects/${projectId}/comments/tasks/${taskId}/`, { comment, }); diff --git a/frontend/src/api/stats.js b/frontend/src/api/stats.ts similarity index 70% rename from frontend/src/api/stats.js rename to frontend/src/api/stats.ts index 1016afac77..59c5701760 100644 --- a/frontend/src/api/stats.js +++ b/frontend/src/api/stats.ts @@ -4,13 +4,16 @@ import { fetchExternalJSONAPI } from '../network/genericJSONRequest'; import api from './apiClient'; import { OHSOME_STATS_BASE_URL, defaultChangesetComment } from '../config'; -const ohsomeProxyAPI = (url) => { +const ohsomeProxyAPI = (url: string) => { const token = localStorage.getItem('token'); + if (!token) return null; return api(token).get(`users/statistics/ohsome/?url=${url}`); }; export const useSystemStatisticsQuery = () => { - const fetchSystemStats = ({ signal }) => { + const fetchSystemStats = ({ signal }: { + signal: AbortSignal; + }) => { return api().get(`system/statistics/`, { signal, }); @@ -19,12 +22,14 @@ export const useSystemStatisticsQuery = () => { return useQuery({ queryKey: ['tm-stats'], queryFn: fetchSystemStats, - useErrorBoundary: true, + throwOnError: true, }); }; -export const useProjectStatisticsQuery = (projectId) => { - const fetchProjectStats = ({ signal }) => { +export const useProjectStatisticsQuery = (projectId: string) => { + const fetchProjectStats = ({ signal }: { + signal: AbortSignal; + }) => { return api().get(`projects/${projectId}/statistics/`, { signal, }); @@ -38,7 +43,9 @@ export const useProjectStatisticsQuery = (projectId) => { }; export const useOsmStatsQuery = () => { - const fetchOsmStats = ({ signal }) => { + const fetchOsmStats = ({ signal }: { + signal: AbortSignal; + }) => { return api().get(`${OHSOME_STATS_BASE_URL}/stats/${defaultChangesetComment}-%2A`, { signal, }); @@ -47,13 +54,15 @@ export const useOsmStatsQuery = () => { return useQuery({ queryKey: ['osm-stats'], queryFn: fetchOsmStats, - useErrorBoundary: true, + throwOnError: true, select: (data) => data.data.result, }); }; -export const useOsmHashtagStatsQuery = (defaultComment) => { - const fetchOsmStats = ({ signal }) => { +export const useOsmHashtagStatsQuery = (defaultComment: string) => { + const fetchOsmStats = ({ signal }: { + signal: AbortSignal; + }) => { return api().get(`${OHSOME_STATS_BASE_URL}/stats/${defaultComment[0].replace('#', '')}`, { signal, }); @@ -62,13 +71,13 @@ export const useOsmHashtagStatsQuery = (defaultComment) => { return useQuery({ queryKey: ['osm-hashtag-stats'], queryFn: fetchOsmStats, - useErrorBoundary: true, + throwOnError: true, enabled: Boolean(defaultComment?.[0]), select: (data) => data.data.result, }); }; -export const useUserOsmStatsQuery = (id) => { +export const useUserOsmStatsQuery = (id: string) => { const fetchUserOsmStats = () => { return ohsomeProxyAPI( `${OHSOME_STATS_BASE_URL}/topic/poi,highway,building,waterway/user?userId=${id}`, @@ -78,9 +87,9 @@ export const useUserOsmStatsQuery = (id) => { return useQuery({ queryKey: ['user-osm-stats'], queryFn: fetchUserOsmStats, - // userDetail.test.js fails on CI when useErrorBoundary=true - useErrorBoundary: process.env.NODE_ENV !== 'test', - select: (data) => data.data.result, + // userDetail.test.js fails on CI when throwOnError=true + throwOnError: import.meta.env.NODE_ENV !== 'test', + select: (data) => data?.data.result, enabled: !!id, }); }; @@ -93,7 +102,7 @@ export const useOsmStatsMetadataQuery = () => { return useQuery({ queryKey: ['osm-stats-metadata'], queryFn: fetchOsmStatsMetadata, - useErrorBoundary: true, + throwOnError: true, select: (data) => data.result, }); }; diff --git a/frontend/src/api/teams.js b/frontend/src/api/teams.ts similarity index 59% rename from frontend/src/api/teams.js rename to frontend/src/api/teams.ts index c79ae9d76a..e17ee39b7d 100644 --- a/frontend/src/api/teams.js +++ b/frontend/src/api/teams.ts @@ -2,11 +2,14 @@ import { useSelector } from 'react-redux'; import { useQuery } from '@tanstack/react-query'; import api from './apiClient'; +import { RootStore } from '../store'; -export const useTeamsQuery = (params, otherOptions) => { - const token = useSelector((state) => state.auth.token); +export const useTeamsQuery = (params: any, otherOptions: any) => { + const token = useSelector((state: RootStore) => state.auth.token); - const fetchUserTeams = ({ signal }) => { + const fetchUserTeams = ({ signal }: { + signal: AbortSignal; + }) => { return api(token).get(`teams/`, { signal, params: params, diff --git a/frontend/src/api/user.js b/frontend/src/api/user.ts similarity index 58% rename from frontend/src/api/user.js rename to frontend/src/api/user.ts index 641baadfea..e83ffb86b3 100644 --- a/frontend/src/api/user.js +++ b/frontend/src/api/user.ts @@ -2,12 +2,15 @@ import { useSelector } from 'react-redux'; import { useQuery } from '@tanstack/react-query'; import api from './apiClient'; +import { RootStore } from '../store'; export const useLockedTasksQuery = () => { - const token = useSelector((state) => state.auth.token); - const locale = useSelector((state) => state.preferences['locale']); + const token = useSelector((state: RootStore) => state.auth.token); + const locale = useSelector((state: RootStore) => state.preferences['locale']); - const fetchLockedTasks = ({ signal }) => { + const fetchLockedTasks = ({ signal }: { + signal: AbortSignal; + }) => { return api(token, locale).get(`users/queries/tasks/locked/details/`, { signal, }); @@ -17,7 +20,6 @@ export const useLockedTasksQuery = () => { queryKey: ['locked-tasks'], queryFn: fetchLockedTasks, select: (data) => data.data?.tasks, - cacheTime: 0, - useErrorBoundary: true, + throwOnError: true, }); }; diff --git a/frontend/src/components/alert/index.js b/frontend/src/components/alert/index.tsx similarity index 78% rename from frontend/src/components/alert/index.js rename to frontend/src/components/alert/index.tsx index 7539c03746..28facb7820 100644 --- a/frontend/src/components/alert/index.js +++ b/frontend/src/components/alert/index.tsx @@ -9,6 +9,12 @@ export const Alert = ({ inline = false, iconClassName, children, +}: { + type: 'info' | 'success' | 'warning' | 'error'; + compact?: boolean; + inline?: boolean; + iconClassName?: string; + children: React.ReactNode; }) => { const icons = { info: InfoIcon, @@ -33,9 +39,8 @@ export const Alert = ({ return (
{children} @@ -43,7 +48,10 @@ export const Alert = ({ ); }; -export function EntityError({ entity, action = 'creation' }) { +export function EntityError({ entity, action = 'creation' }: { + entity: string; + action?: 'creation' | 'updation'; +}) { const messageType = action === 'updation' ? 'entityInfoUpdationFailure' : 'entityCreationFailure'; return ( diff --git a/frontend/src/components/alert/tests/index.test.js b/frontend/src/components/alert/tests/index.test.tsx similarity index 89% rename from frontend/src/components/alert/tests/index.test.js rename to frontend/src/components/alert/tests/index.test.tsx index 3b28c1c35d..b1a281ec9b 100644 --- a/frontend/src/components/alert/tests/index.test.js +++ b/frontend/src/components/alert/tests/index.test.tsx @@ -7,7 +7,7 @@ describe('Alert Component', () => { const { container } = render(An error message); expect(container.querySelector('svg')).toBeInTheDocument(); // ban icon expect(container.querySelector('.dark-red')).toBeInTheDocument(); - expect(container.querySelector('div').className).toBe( + expect(container.querySelector('div')?.className).toBe( 'db blue-dark bl bw2 br2 pa3 b--dark-red bg-washed-red', ); expect(screen.queryByText(/An error message/)).toBeInTheDocument(); @@ -21,7 +21,7 @@ describe('Alert Component', () => { ); expect(container.querySelector('svg')).toBeInTheDocument(); expect(container.querySelector('.dark-green')).toBeInTheDocument(); - const divClassName = container.querySelector('div').className; + const divClassName = container.querySelector('div')?.className; expect(divClassName).toContain('b--dark-green bg-washed-green'); expect(divClassName).toContain('di'); expect(divClassName).not.toContain('db'); @@ -36,7 +36,7 @@ describe('Alert Component', () => { ); expect(container.querySelector('svg')).toBeInTheDocument(); expect(container.querySelector('.blue')).toBeInTheDocument(); - const divClassName = container.querySelector('div').className; + const divClassName = container.querySelector('div')?.className; expect(divClassName).toContain('b--blue bg-lightest-blue'); expect(divClassName).toContain('db'); expect(divClassName).not.toContain('di'); @@ -53,7 +53,7 @@ describe('Alert Component', () => { ); expect(container.querySelector('svg')).toBeInTheDocument(); expect(container.querySelector('.gold')).toBeInTheDocument(); - const divClassName = container.querySelector('div').className; + const divClassName = container.querySelector('div')?.className; expect(divClassName).toContain('b--gold bg-washed-yellow'); expect(divClassName).toContain('di'); expect(divClassName).toContain('pa2'); diff --git a/frontend/src/components/banner/index.js b/frontend/src/components/banner/index.tsx similarity index 100% rename from frontend/src/components/banner/index.js rename to frontend/src/components/banner/index.tsx diff --git a/frontend/src/components/banner/messages.js b/frontend/src/components/banner/messages.ts similarity index 100% rename from frontend/src/components/banner/messages.js rename to frontend/src/components/banner/messages.ts diff --git a/frontend/src/components/banner/tests/topBanner.test.js b/frontend/src/components/banner/tests/topBanner.test.tsx similarity index 100% rename from frontend/src/components/banner/tests/topBanner.test.js rename to frontend/src/components/banner/tests/topBanner.test.tsx diff --git a/frontend/src/components/banner/topBanner.js b/frontend/src/components/banner/topBanner.tsx similarity index 57% rename from frontend/src/components/banner/topBanner.js rename to frontend/src/components/banner/topBanner.tsx index 7cc1bcf895..cf65aee73f 100644 --- a/frontend/src/components/banner/topBanner.js +++ b/frontend/src/components/banner/topBanner.tsx @@ -2,18 +2,30 @@ import { useLocation } from 'react-router-dom'; import { useFetchWithAbort } from '../../hooks/UseFetch'; import { htmlFromMarkdown } from '../../utils/htmlFromMarkdown'; import './styles.scss'; +import { useEffect, useState } from 'react'; export function TopBanner() { const location = useLocation(); const [, error, data] = useFetchWithAbort(`system/banner/`); + const [dangerousInner, setDangerousInner] = useState(null); + + useEffect(() => { + (async () => { + // @ts-expect-error + setDangerousInner((await htmlFromMarkdown(data?.message)).__html) + }) + }, [data]) return ( <> + {/* @ts-expect-error TS Migrations */} {location.pathname === '/' && data.visible && !error && (
)} diff --git a/frontend/src/components/button.js b/frontend/src/components/button.tsx similarity index 54% rename from frontend/src/components/button.js rename to frontend/src/components/button.tsx index af665a7a92..cd429e5ace 100644 --- a/frontend/src/components/button.js +++ b/frontend/src/components/button.tsx @@ -3,22 +3,31 @@ import { Link } from 'react-router-dom'; import { LoadingIcon } from './svgIcons'; import React from 'react'; -const IconSpace = ({ children }) => {children}; +const IconSpace = ({ children }: { + children: React.ReactNode, +}) => {children}; export const AnimatedLoadingIcon = () => ( ); -export function Button({ onClick, children, icon, className, disabled, loading = false }: Object) { +export type ButtonProps = React.ButtonHTMLAttributes & { + icon?: React.ReactNode, + loading?: boolean, +}; + +export function Button(props: ButtonProps) { + const { children, icon, className, loading = false, disabled, ...rest } = props + return ( ); -}); +}; export const AuthButtons = ({ logInStyle, signUpStyle, redirectTo, alternativeSignUpText = false, +}: { + logInStyle: string; + signUpStyle: string; + redirectTo: string; + alternativeSignUpText?: boolean; }) => { const [debouncedCreateLoginWindow] = useDebouncedCallback( (redirectToPass) => createLoginWindow(redirectToPass), @@ -251,7 +264,12 @@ export const AuthButtons = ({ ); }; -export const ActionItems = ({ userDetails, onUserMenuSelect, location, getUserLinks }) => +export const ActionItems = ({ userDetails, onUserMenuSelect, location, getUserLinks }: { + userDetails: any; + onUserMenuSelect: (e: any) => void; + location: any; + getUserLinks: (role: string) => any; +}) => userDetails.username ? ( <> @@ -274,6 +292,7 @@ export const ActionItems = ({ userDetails, onUserMenuSelect, location, getUserLi ); + export const PopupItems = (props) => { const dispatch = useDispatch(); diff --git a/frontend/src/components/header/messages.js b/frontend/src/components/header/messages.ts similarity index 100% rename from frontend/src/components/header/messages.js rename to frontend/src/components/header/messages.ts diff --git a/frontend/src/components/header/notificationBell.js b/frontend/src/components/header/notificationBell.jsx similarity index 100% rename from frontend/src/components/header/notificationBell.js rename to frontend/src/components/header/notificationBell.jsx diff --git a/frontend/src/components/header/signUp.js b/frontend/src/components/header/signUp.js deleted file mode 100644 index d56f9b1167..0000000000 --- a/frontend/src/components/header/signUp.js +++ /dev/null @@ -1,227 +0,0 @@ -import { useState } from 'react'; -import { FormattedMessage } from 'react-intl'; - -import messages from './messages'; -import { Button } from '../button'; -import { CloseIcon } from '../svgIcons'; -import { registerUser } from '../../store/actions/user'; -import { store } from '../../store'; -import { createLoginWindow } from '../../utils/login'; -import { ORG_PRIVACY_POLICY_URL, OSM_REGISTER_URL } from '../../config'; -import { setItem } from '../../utils/safe_storage'; - -export const LoginModal = ({ step, login }) => { - return ( -
-

- {step.number}. - -

-
-

- -

-
-
- -

- - - -

-
-
- ); -}; - -export const ProceedOSM = ({ data, step, setStep, login }) => { - const NextStep = (setStep) => { - window.open(OSM_REGISTER_URL, '_blank'); - setStep((s) => { - return { ...s, number: 3 }; - }); - }; - - const handleLogin = () => { - login(); - setItem('email_address', data.email); - setItem('name', data.name); - }; - - return ( -
-

- {step.number}. - -

-
-

- -

-

- -

-
-
- -

handleLogin()}> - -

-
-
- ); -}; - -const SignupForm = ({ data, setData, step, setStep }) => { - const onChange = (e) => { - setData({ ...data, [e.target.name]: e.target.value }); - if (step.errMessage) setStep({ ...step, errMessage: null }); - }; - - const checkFields = () => { - const re = - // eslint-disable-next-line no-useless-escape - /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - if (re.test(data.email) === false) { - setStep({ ...step, errMessage: }); - return; - } - - const formData = { - email: data.email, - }; - - const registerPromise = store.dispatch(registerUser(formData)); - registerPromise.then((res) => { - if (res.success === true) { - setItem('email_address', data.email); - setItem('name', data.name); - setStep({ number: 2, errMessage: null }); - } else { - setStep({ number: 1, errMessage: res.details }); - } - }); - }; - - return ( -
-

- {step.number}. - -

-

- -

-
-
-

- -

- - {(msg) => { - return ( - - ); - }} - -
-
-

- -

- - {(msg) => { - return ( - - ); - }} - -
-

- {step.errMessage} -

-
- {ORG_PRIVACY_POLICY_URL && ( -

- - - -

- )} -
- -
-
- ); -}; - -export const SignUp = ({ closeModal }) => { - const [data, setData] = useState({ name: '', email: '' }); - const [step, setStep] = useState({ number: 1, errMessage: null }); - - const login = () => { - let redirect = '/welcome'; - if (window.location.pathname.startsWith('/projects')) { - redirect = window.location.pathname; - } - - closeModal(); - createLoginWindow(redirect); - }; - - const getStep = (step) => { - switch (step.number) { - case 2: - return ; - case 3: - return ; - default: - return ; - } - }; - - return ( -
- closeModal()}> - - - {getStep(step)} -
- ); -}; diff --git a/frontend/src/components/header/signUp.tsx b/frontend/src/components/header/signUp.tsx new file mode 100644 index 0000000000..ff00117923 --- /dev/null +++ b/frontend/src/components/header/signUp.tsx @@ -0,0 +1,266 @@ +import { FormattedMessage } from 'react-intl'; +import messages from './messages'; +import { CloseIcon } from '../svgIcons'; +import { registerUser } from '../../store/actions/user'; +import { store } from '../../store'; +import { ORG_PRIVACY_POLICY_URL, OSM_REGISTER_URL } from '../../config'; +import { setItem } from '../../utils/safe_storage'; +import { Button } from '../button'; +import { useState } from 'react'; + +export const LoginModal = ({ step, login }: { + step: { number: number; errMessage: React.ReactNode }; + login: () => void; +}) => { + return ( +
+

+ {step.number}. + +

+
+

+ +

+
+
+ +

+ + + +

+
+
+
+
+ ); +}; + +export const ProceedOSM = ({ data, step, setStep, login }: { + data: { email: string; name: string }; + step: { number: number; errMessage: React.ReactNode }; + setStep: React.Dispatch> + login: () => void; +}) => { + const NextStep = () => { + window.open(OSM_REGISTER_URL, '_blank'); + setStep((s) => { + return { ...s, number: 3 }; + }); + }; + + const handleLogin = () => { + login(); + setItem('email_address', data.email); + setItem('name', data.name); + }; + + return ( +
+

+ {step.number}. + +

+
+

+ +

+

+ +

+
+
+ +

handleLogin()}> + +

+
+
+
+
+ ); +}; + +const SignupForm = ({ data, setData, step, setStep }: { + data: { email: string; name: string }; + setData: React.Dispatch>; + step: { number: number; errMessage: React.ReactNode }; + setStep: React.Dispatch>; +}) => { + const onChange = (e: React.ChangeEvent) => { + setData({ ...data, [e.target.name]: e.target.value }); + if (step.errMessage) setStep({ ...step, errMessage: null }); + }; + + const checkFields = () => { + const re = + // eslint-disable-next-line no-useless-escape + /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1, 3}\.[0-9]{1, 3}\.[0-9]{1, 3}\.[0-9]{1, 3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + if (re.test(data.email) === false) { + setStep({ ...step, errMessage: }); + return; + } + + const formData = { + email: data.email, + }; + + // @ts-expect-error TS Migration + const registerPromise = store.dispatch(registerUser(formData)); + // @ts-expect-error TS Migration + registerPromise.then((res) => { + if (res.success === true) { + setItem('email_address', data.email); + setItem('name', data.name); + setStep({ number: 2, errMessage: null }); + } else { + setStep({ number: 1, errMessage: res.details }); + } + }); + }; + + return ( +
+

+ {step.number}. + +

+

+ +

+
+
+

+ +

+ + {(msg) => { + return ( + + ); + }} + +
+
+

+ +

+ + {(msg) => { + return ( + + ); + }} + +

+ {step.errMessage} +

+
+ { + ORG_PRIVACY_POLICY_URL && ( +

+ + + +

+ )} +
+ +
+
+
+ ); +}; + +export const SignUp = ({ closeModal, createLoginWindow }: { + closeModal: () => void, + createLoginWindow: (redirect: string) => void, +}) => { + const [data, setData] = useState({ name: '', email: '' }); + const [step, setStep] = useState<{ + number: number; + errMessage: React.ReactNode; + }>({ number: 1, errMessage: null }); + + const login = () => { + let redirect = '/welcome'; + if (window.location.pathname.startsWith('/projects')) { + redirect = window.location.pathname; + } + + closeModal(); + createLoginWindow(redirect); + }; + + const getStep = (step: { + number: number; + errMessage: React.ReactNode; + }) => { + switch (step.number) { + case 2: + return ; + case 3: + return ; + default: + return ; + } + }; + + return ( +
+ closeModal()}> + + + {getStep(step)} +
+ ); +}; diff --git a/frontend/src/components/header/updateDialog.js b/frontend/src/components/header/updateDialog.jsx similarity index 100% rename from frontend/src/components/header/updateDialog.js rename to frontend/src/components/header/updateDialog.jsx diff --git a/frontend/src/components/header/updateEmail.js b/frontend/src/components/header/updateEmail.tsx similarity index 89% rename from frontend/src/components/header/updateEmail.js rename to frontend/src/components/header/updateEmail.tsx index 6eb44f3eaf..fd7cab4f4c 100644 --- a/frontend/src/components/header/updateEmail.js +++ b/frontend/src/components/header/updateEmail.tsx @@ -7,13 +7,16 @@ import messages from './messages'; import { updateUserEmail } from '../../store/actions/auth'; import { PROFILE_RELEVANT_FIELDS } from '../user/forms/personalInformation'; import { ORG_PRIVACY_POLICY_URL } from '../../config'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; +import { RootStore } from '../../store/index.js'; -export const UpdateEmail = ({ closeModal }) => { +export const UpdateEmail = ({ closeModal }: { + closeModal: () => void; +}) => { const dispatch = useDispatch(); - const userDetails = useSelector((state) => state.auth.userDetails); - const token = useSelector((state) => state.auth.token); + const userDetails = useSelector((state: RootStore) => state.auth.userDetails); + const token = useSelector((state: RootStore) => state.auth.token); const [userState, setUserState] = useState({ email: '', success: false, details: '' }); const onChange = (e) => { diff --git a/frontend/src/components/homepage/jumbotron.js b/frontend/src/components/homepage/jumbotron.jsx similarity index 100% rename from frontend/src/components/homepage/jumbotron.js rename to frontend/src/components/homepage/jumbotron.jsx diff --git a/frontend/src/components/homepage/mappingFlow.js b/frontend/src/components/homepage/mappingFlow.jsx similarity index 96% rename from frontend/src/components/homepage/mappingFlow.js rename to frontend/src/components/homepage/mappingFlow.jsx index 261b58bb44..1f56217d40 100644 --- a/frontend/src/components/homepage/mappingFlow.js +++ b/frontend/src/components/homepage/mappingFlow.jsx @@ -4,7 +4,7 @@ import messages from './messages'; import { MappingIcon, ValidationIcon, DataUseIcon } from '../svgIcons'; import './styles.scss'; -function MappingCard({ image, title, description }: Object) { +function MappingCard({ image, title, description }) { return (
diff --git a/frontend/src/components/homepage/stats.js b/frontend/src/components/homepage/stats.jsx similarity index 97% rename from frontend/src/components/homepage/stats.js rename to frontend/src/components/homepage/stats.jsx index 1901fa35f4..77edfb9ebb 100644 --- a/frontend/src/components/homepage/stats.js +++ b/frontend/src/components/homepage/stats.jsx @@ -17,7 +17,7 @@ export const StatsNumber = (props) => { ); }; -export const StatsColumn = ({ label, value }: Object) => { +export const StatsColumn = ({ label, value }) => { return (
diff --git a/frontend/src/components/homepage/testimonials.js b/frontend/src/components/homepage/testimonials.jsx similarity index 100% rename from frontend/src/components/homepage/testimonials.js rename to frontend/src/components/homepage/testimonials.jsx diff --git a/frontend/src/components/homepage/whoIsMapping.js b/frontend/src/components/homepage/whoIsMapping.jsx similarity index 100% rename from frontend/src/components/homepage/whoIsMapping.js rename to frontend/src/components/homepage/whoIsMapping.jsx diff --git a/frontend/src/components/horizontalScroll/index.js b/frontend/src/components/horizontalScroll/index.tsx similarity index 71% rename from frontend/src/components/horizontalScroll/index.js rename to frontend/src/components/horizontalScroll/index.tsx index 04216b2035..7350c59c47 100644 --- a/frontend/src/components/horizontalScroll/index.js +++ b/frontend/src/components/horizontalScroll/index.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, RefObject } from 'react'; import { ChevronRightIcon } from '../svgIcons'; import { useWindowSize } from '../../hooks/UseWindowSize'; @@ -10,6 +10,12 @@ export function HorizontalScroll({ containerClass, style = {}, children, +}: { + className?: string; + menuItemsContainerRef: RefObject; + containerClass: string; + style?: React.CSSProperties; + children: React.ReactNode; }) { const [scrollLeft, setScrollLeft] = useState(0); // This triggers rerender when the screen size changes, so had to keep it @@ -26,11 +32,12 @@ export function HorizontalScroll({ }; }, [containerClass]); - const updateScrollLeft = (e) => { + const updateScrollLeft = (e: Event) => { + // @ts-expect-error TS Migrations setScrollLeft(e.target.scrollLeft); }; - const handleScroll = (direction) => { + const handleScroll = (direction: "left" | "right") => { let currentScroll = scrollLeft; if (direction === 'right') { currentScroll += 200; @@ -46,9 +53,8 @@ export function HorizontalScroll({ return (
0 ? 'flex items-center' : 'dn' - }`} + className={`bg-white left-icon absolute h-100 left-0 top-0 rotate-180 z-1 h-100 pointer pa2 translate-icon-btm ${scrollLeft > 0 ? 'flex items-center' : 'dn' + }`} role="button" onClick={() => handleScroll('left')} > @@ -56,14 +62,13 @@ export function HorizontalScroll({
handleScroll('right')} > diff --git a/frontend/src/components/interests/index.js b/frontend/src/components/interests/index.js index b0227f8915..d782090be1 100644 --- a/frontend/src/components/interests/index.js +++ b/frontend/src/components/interests/index.js @@ -7,7 +7,7 @@ import ReactPlaceholder from 'react-placeholder'; import messages from '../teamsAndOrgs/messages'; import { Management } from '../teamsAndOrgs/management'; import { HashtagIcon } from '../svgIcons'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { nCardPlaceholders } from '../teamsAndOrgs/campaignsPlaceholder'; import { TextField } from '../formInputs'; diff --git a/frontend/src/components/licenses/index.js b/frontend/src/components/licenses/index.js index 7ec1db9981..f5676c037f 100644 --- a/frontend/src/components/licenses/index.js +++ b/frontend/src/components/licenses/index.js @@ -7,7 +7,7 @@ import ReactPlaceholder from 'react-placeholder'; import messages from '../teamsAndOrgs/messages'; import { Management } from '../teamsAndOrgs/management'; import { CopyrightIcon } from '../svgIcons'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { nCardPlaceholders } from './licensesPlaceholder'; import { TextField } from '../formInputs'; diff --git a/frontend/src/components/localeSelect.js b/frontend/src/components/localeSelect.tsx similarity index 81% rename from frontend/src/components/localeSelect.js rename to frontend/src/components/localeSelect.tsx index 5c716723a9..7ebc43fa7d 100644 --- a/frontend/src/components/localeSelect.js +++ b/frontend/src/components/localeSelect.tsx @@ -5,6 +5,7 @@ import Select from 'react-select'; import messages from './messages'; import { supportedLocales } from '../utils/internationalization'; import { setLocale } from '../store/actions/userPreferences'; +import { RootStore } from '../store'; function LocaleSelect({ className, @@ -12,14 +13,26 @@ function LocaleSelect({ setLocale, removeBorder = true, fullWidth = false, +}: { + className?: string; + userPreferences: { locale: string }; + setLocale: (locale: string) => void; + removeBorder?: boolean; + fullWidth?: boolean; }) { - const onLocaleSelect = (arr) => { + const onLocaleSelect = (arr: { + value: string; + label: string; + }[]) => { setLocale(arr[0].value); }; const getActiveLanguageNames = () => { const locales = [userPreferences.locale, navigator.language, navigator.language.substr(0, 2)]; - let supportedLocaleNames = []; + const supportedLocaleNames: { + value: string; + label: string + }[] = []; locales.forEach((locale) => supportedLocales .filter((i) => i.value === locale) @@ -55,7 +68,7 @@ function LocaleSelect({ ); } -const mapStateToProps = (state) => ({ +const mapStateToProps = (state: RootStore) => ({ userPreferences: state.preferences, }); diff --git a/frontend/src/components/messages.js b/frontend/src/components/messages.ts similarity index 100% rename from frontend/src/components/messages.js rename to frontend/src/components/messages.ts diff --git a/frontend/src/components/notifications/actionButtons.js b/frontend/src/components/notifications/actionButtons.jsx similarity index 96% rename from frontend/src/components/notifications/actionButtons.js rename to frontend/src/components/notifications/actionButtons.jsx index d2f2c96f33..49e9ea708e 100644 --- a/frontend/src/components/notifications/actionButtons.js +++ b/frontend/src/components/notifications/actionButtons.jsx @@ -84,9 +84,9 @@ export const ActionButtons = ({ isAllSelected ? updateUnreadCount() : // The decrement count is readily available; deducting count from selected - Array.from({ length: unreadCountInSelected }, () => - dispatch({ type: 'DECREMENT_UNREAD_COUNT' }), - ); + Array.from({ length: unreadCountInSelected }, () => + dispatch({ type: 'DECREMENT_UNREAD_COUNT' }), + ); } if (selected.length) { diff --git a/frontend/src/components/notifications/inboxNav.js b/frontend/src/components/notifications/inboxNav.jsx similarity index 100% rename from frontend/src/components/notifications/inboxNav.js rename to frontend/src/components/notifications/inboxNav.jsx diff --git a/frontend/src/components/notifications/messages.js b/frontend/src/components/notifications/messages.ts similarity index 100% rename from frontend/src/components/notifications/messages.js rename to frontend/src/components/notifications/messages.ts diff --git a/frontend/src/components/notifications/notificationBodyCard.js b/frontend/src/components/notifications/notificationBodyCard.jsx similarity index 99% rename from frontend/src/components/notifications/notificationBodyCard.js rename to frontend/src/components/notifications/notificationBodyCard.jsx index 27bc692e06..00e2c17dd5 100644 --- a/frontend/src/components/notifications/notificationBodyCard.js +++ b/frontend/src/components/notifications/notificationBodyCard.jsx @@ -87,7 +87,7 @@ export function NotificationBodyCard({ message, sentDate, }, -}: Object) { +}) { const token = useSelector((state) => state.auth.token); const { value, unit } = selectUnit(new Date((sentDate && new Date(sentDate)) || new Date())); const showASendingUser = diff --git a/frontend/src/components/notifications/notificationCard.js b/frontend/src/components/notifications/notificationCard.jsx similarity index 99% rename from frontend/src/components/notifications/notificationCard.js rename to frontend/src/components/notifications/notificationCard.jsx index b5e1486e7b..1f830ba50d 100644 --- a/frontend/src/components/notifications/notificationCard.js +++ b/frontend/src/components/notifications/notificationCard.jsx @@ -25,7 +25,7 @@ export const stripHtmlToText = (notificationHtml) => export const typesThatUseSystemAvatar = ['SYSTEM', 'REQUEST_TEAM_NOTIFICATION']; -export const MessageAvatar = ({ messageType, fromUsername, displayPictureUrl, size }: Object) => { +export const MessageAvatar = ({ messageType, fromUsername, displayPictureUrl, size }) => { const checkIsSystem = typesThatUseSystemAvatar.indexOf(messageType) !== -1; if (!fromUsername && !checkIsSystem) { @@ -68,7 +68,7 @@ export function NotificationCard({ retryFn, selected, setSelected, -}: Object) { +}) { const dispatch = useDispatch(); const token = useSelector((state) => state.auth.token); const ref = useRef(); @@ -201,7 +201,7 @@ export function NotificationCardMini({ setPopoutFocus, retryFn, read, -}: Object) { +}) { const dispatch = useDispatch(); const setMessageAsRead = () => { diff --git a/frontend/src/components/notifications/notificationOrderBy.js b/frontend/src/components/notifications/notificationOrderBy.jsx similarity index 100% rename from frontend/src/components/notifications/notificationOrderBy.js rename to frontend/src/components/notifications/notificationOrderBy.jsx diff --git a/frontend/src/components/notifications/notificationPlaceholder.js b/frontend/src/components/notifications/notificationPlaceholder.jsx similarity index 100% rename from frontend/src/components/notifications/notificationPlaceholder.js rename to frontend/src/components/notifications/notificationPlaceholder.jsx diff --git a/frontend/src/components/notifications/notificationResults.js b/frontend/src/components/notifications/notificationResults.jsx similarity index 100% rename from frontend/src/components/notifications/notificationResults.js rename to frontend/src/components/notifications/notificationResults.jsx diff --git a/frontend/src/components/notifications/paginator.js b/frontend/src/components/notifications/paginator.jsx similarity index 100% rename from frontend/src/components/notifications/paginator.js rename to frontend/src/components/notifications/paginator.jsx diff --git a/frontend/src/components/notifications/selectAllNotifications.js b/frontend/src/components/notifications/selectAllNotifications.jsx similarity index 100% rename from frontend/src/components/notifications/selectAllNotifications.js rename to frontend/src/components/notifications/selectAllNotifications.jsx diff --git a/frontend/src/components/paginator/index.js b/frontend/src/components/paginator/index.jsx similarity index 98% rename from frontend/src/components/paginator/index.js rename to frontend/src/components/paginator/index.jsx index 7dd5742cce..80d1e90be4 100644 --- a/frontend/src/components/paginator/index.js +++ b/frontend/src/components/paginator/index.jsx @@ -66,7 +66,7 @@ export const PageButton = (props) => { } }; -export function PaginatorLine({ activePage, lastPage, setPageFn, className }: Object) { +export function PaginatorLine({ activePage, lastPage, setPageFn, className }) { const pageOptions = listPageOptions(activePage, lastPage); return (
diff --git a/frontend/src/components/partners/currentProjects.js b/frontend/src/components/partners/currentProjects.js index ee88fe296e..3236bc8c01 100644 --- a/frontend/src/components/partners/currentProjects.js +++ b/frontend/src/components/partners/currentProjects.js @@ -6,7 +6,7 @@ import { Pagination } from 'swiper/modules'; import { Swiper, SwiperSlide } from 'swiper/react'; import { TasksMap } from '../taskSelection/map'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { API_URL } from '../../config'; import messages from './messages'; import ProjectProgressBar from '../projectCard/projectProgressBar'; @@ -113,7 +113,7 @@ export function CurrentProjects({ currentProjects }) {

{project.info && project.info.name}

diff --git a/frontend/src/components/preloader.js b/frontend/src/components/preloader.tsx similarity index 100% rename from frontend/src/components/preloader.js rename to frontend/src/components/preloader.tsx diff --git a/frontend/src/components/projectCreate/messages.js b/frontend/src/components/projectCreate/messages.ts similarity index 100% rename from frontend/src/components/projectCreate/messages.js rename to frontend/src/components/projectCreate/messages.ts diff --git a/frontend/src/components/projectCreate/navButtons.js b/frontend/src/components/projectCreate/navButtons.tsx similarity index 82% rename from frontend/src/components/projectCreate/navButtons.js rename to frontend/src/components/projectCreate/navButtons.tsx index eb80376edf..5456cc675e 100644 --- a/frontend/src/components/projectCreate/navButtons.js +++ b/frontend/src/components/projectCreate/navButtons.tsx @@ -2,10 +2,25 @@ import { featureCollection } from '@turf/helpers'; import { FormattedMessage, useIntl } from 'react-intl'; import messages from './messages'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { useAsync } from '../../hooks/UseAsync'; -const clearParamsStep = (props) => { +const clearParamsStep = (props: { + index: number; + metadata: { + area: number; + arbitraryTasks: boolean; + geom: any; + taskGrid: any; + tempTaskGrid: any; + tasksNumber: number; + }; + maxArea: number; + mapObj: any; + setStep: (step: number) => void; + updateMetadata: (metadata: any) => void; + setErr: (err: { error: boolean; message: string }) => void; +}) => { switch (props.index) { case 2: //clear Tasks props.mapObj.map.getSource('grid').setData(featureCollection([])); @@ -39,7 +54,7 @@ const clearParamsStep = (props) => { props.setStep(prevStep); }; -const NavButtons = (props) => { +const NavButtons = (props: any) => { const intl = useIntl(); const createProjectFn = () => { @@ -47,7 +62,21 @@ const NavButtons = (props) => { }; const createProjectAsync = useAsync(createProjectFn); - const validateStep = (props) => { + const validateStep = (props: { + index: number; + metadata: { + area: number; + arbitraryTasks: boolean; + geom: any; + taskGrid: any; + tempTaskGrid: any; + tasksNumber: number; + }; + maxArea: number; + mapObj: any; + setStep: (step: number) => void; + updateMetadata: (metadata: any) => void; + }) => { switch (props.index) { case 1: // Set Project AOI. if (props.metadata.area >= props.maxArea) { @@ -90,7 +119,7 @@ const NavButtons = (props) => { props.setStep(nextStep); return { error: false, message: '' }; }; - const stepHandler = (event) => { + const stepHandler = () => { const resp = validateStep(props); props.setErr(resp); }; diff --git a/frontend/src/components/projectDetail/footer.js b/frontend/src/components/projectDetail/footer.js index 05f8fe1910..aeab6719ef 100644 --- a/frontend/src/components/projectDetail/footer.js +++ b/frontend/src/components/projectDetail/footer.js @@ -3,7 +3,7 @@ import { Link } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { FormattedMessage } from 'react-intl'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import messages from './messages'; import { ShareButton } from './shareButton'; import { AddToFavorites } from './favorites'; @@ -61,9 +61,8 @@ export const ProjectDetailFooter = ({ className, projectId }) => { return (
{/* TODO ADD ANCHORS */} diff --git a/frontend/src/components/projectDetail/messages.js b/frontend/src/components/projectDetail/messages.ts similarity index 100% rename from frontend/src/components/projectDetail/messages.js rename to frontend/src/components/projectDetail/messages.ts diff --git a/frontend/src/components/projectDetail/privateProjectError.js b/frontend/src/components/projectDetail/privateProjectError.js index c357b8f53d..fd01c84d7d 100644 --- a/frontend/src/components/projectDetail/privateProjectError.js +++ b/frontend/src/components/projectDetail/privateProjectError.js @@ -3,7 +3,7 @@ import { FormattedMessage } from 'react-intl'; import messages from './messages'; import { LockIcon } from '../svgIcons'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; const PrivateProjectError = () => { const navigate = useNavigate(); diff --git a/frontend/src/components/projectDetail/questionsAndComments.js b/frontend/src/components/projectDetail/questionsAndComments.js index 4fb083ef64..d69ac509d3 100644 --- a/frontend/src/components/projectDetail/questionsAndComments.js +++ b/frontend/src/components/projectDetail/questionsAndComments.js @@ -7,7 +7,7 @@ import ReactPlaceholder from 'react-placeholder'; import messages from './messages'; import { RelativeTimeWithUnit } from '../../utils/formattedRelativeTime'; import { PaginatorLine } from '../paginator'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { Alert } from '../alert'; import { MessageStatus } from '../comments/status'; import { UserAvatar } from '../user/avatar'; diff --git a/frontend/src/components/projectDetail/statusBox.js b/frontend/src/components/projectDetail/statusBox.tsx similarity index 70% rename from frontend/src/components/projectDetail/statusBox.js rename to frontend/src/components/projectDetail/statusBox.tsx index 35d1a27343..a073d078ce 100644 --- a/frontend/src/components/projectDetail/statusBox.js +++ b/frontend/src/components/projectDetail/statusBox.tsx @@ -2,7 +2,10 @@ import { FormattedMessage } from 'react-intl'; import messages from './messages'; -export const ProjectStatusBox = ({ status, className }: Object) => { +export const ProjectStatusBox = ({ status, className }: { + status: "DRAFT" | "PUBLISHED" | "ARCHIVED", + className: string, +}) => { const colour = status === 'DRAFT' ? 'orange' : 'blue-grey'; return (
diff --git a/frontend/src/components/projectDetail/timeline.js b/frontend/src/components/projectDetail/timeline.tsx similarity index 93% rename from frontend/src/components/projectDetail/timeline.js rename to frontend/src/components/projectDetail/timeline.tsx index c62efbb854..c32b410247 100644 --- a/frontend/src/components/projectDetail/timeline.js +++ b/frontend/src/components/projectDetail/timeline.tsx @@ -28,7 +28,11 @@ ChartJS.register( Tooltip, ); -export default function ProjectTimeline({ tasksByDay }: Object) { +export default function ProjectTimeline({ tasksByDay }: { + tasksByDay: { + date: string; + }[] +}) { const intl = useIntl(); const unit = useTimeDiff(tasksByDay); const mappedTasksConfig = { diff --git a/frontend/src/components/projectEdit/actionsForm.js b/frontend/src/components/projectEdit/actionsForm.js index d9f1561027..f1a25b2393 100644 --- a/frontend/src/components/projectEdit/actionsForm.js +++ b/frontend/src/components/projectEdit/actionsForm.js @@ -6,7 +6,7 @@ import { useNavigate } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { Alert } from '../alert'; import { DeleteModal } from '../deleteModal'; import { styleClasses, StateContext } from '../../views/projectEdit'; diff --git a/frontend/src/components/projectEdit/partnersForm.js b/frontend/src/components/projectEdit/partnersForm.js index 4cc2ab1b79..428a33c359 100644 --- a/frontend/src/components/projectEdit/partnersForm.js +++ b/frontend/src/components/projectEdit/partnersForm.js @@ -12,7 +12,7 @@ import PropTypes from 'prop-types'; import messages from './messages'; import { Alert } from '../alert'; import { ChevronDownIcon, CloseIcon } from '../svgIcons'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { styleClasses } from '../../views/projectEdit'; import { pushToLocalJSONAPI } from '../../network/genericJSONRequest'; import { useAllPartnersQuery } from '../../api/projects'; diff --git a/frontend/src/components/projectEdit/partnersListing.js b/frontend/src/components/projectEdit/partnersListing.js index 80558f9835..1b7f68dad0 100644 --- a/frontend/src/components/projectEdit/partnersListing.js +++ b/frontend/src/components/projectEdit/partnersListing.js @@ -14,7 +14,7 @@ import PropTypes from 'prop-types'; import messages from './messages'; import { Alert } from '../alert'; import { BanIcon, CircleMinusIcon, CircleExclamationIcon } from '../svgIcons'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { styleClasses } from '../../views/projectEdit'; import { fetchLocalJSONAPI, pushToLocalJSONAPI } from '../../network/genericJSONRequest'; import { DateCustomInput } from './partnersForm'; diff --git a/frontend/src/components/projectEdit/teamSelect.js b/frontend/src/components/projectEdit/teamSelect.js index 3a97b3fafc..14b9e5ec09 100644 --- a/frontend/src/components/projectEdit/teamSelect.js +++ b/frontend/src/components/projectEdit/teamSelect.js @@ -4,7 +4,7 @@ import { FormattedMessage, useIntl } from 'react-intl'; import messages from './messages'; import commonMessages from '../messages'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { StateContext } from '../../views/projectEdit'; import { PencilIcon, WasteIcon, ExternalLinkIcon } from '../svgIcons'; import { useFetchWithAbort } from '../../hooks/UseFetch'; diff --git a/frontend/src/components/projects/clearFilters.js b/frontend/src/components/projects/clearFilters.tsx similarity index 72% rename from frontend/src/components/projects/clearFilters.js rename to frontend/src/components/projects/clearFilters.tsx index 2104594b24..85af8d55d7 100644 --- a/frontend/src/components/projects/clearFilters.js +++ b/frontend/src/components/projects/clearFilters.tsx @@ -3,7 +3,10 @@ import { FormattedMessage } from 'react-intl'; import messages from './messages'; -export default function ClearFilters({ url, className = '' }: Object) { +export default function ClearFilters({ url, className = '' }: { + url: string; + className?: string; +}) { return ( diff --git a/frontend/src/components/projects/filterSelectFields.js b/frontend/src/components/projects/filterSelectFields.jsx similarity index 100% rename from frontend/src/components/projects/filterSelectFields.js rename to frontend/src/components/projects/filterSelectFields.jsx diff --git a/frontend/src/components/projects/list.js b/frontend/src/components/projects/list.jsx similarity index 100% rename from frontend/src/components/projects/list.js rename to frontend/src/components/projects/list.jsx diff --git a/frontend/src/components/projects/mappingTypeFilterPicker.js b/frontend/src/components/projects/mappingTypeFilterPicker.jsx similarity index 100% rename from frontend/src/components/projects/mappingTypeFilterPicker.js rename to frontend/src/components/projects/mappingTypeFilterPicker.jsx diff --git a/frontend/src/components/projects/messages.js b/frontend/src/components/projects/messages.ts similarity index 100% rename from frontend/src/components/projects/messages.js rename to frontend/src/components/projects/messages.ts diff --git a/frontend/src/components/projects/moreFiltersForm.js b/frontend/src/components/projects/moreFiltersForm.jsx similarity index 99% rename from frontend/src/components/projects/moreFiltersForm.js rename to frontend/src/components/projects/moreFiltersForm.jsx index 3545a214b0..406d05cdc9 100644 --- a/frontend/src/components/projects/moreFiltersForm.js +++ b/frontend/src/components/projects/moreFiltersForm.jsx @@ -4,7 +4,7 @@ import { useQueryParam, BooleanParam } from 'use-query-params'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { SwitchToggle } from '../formInputs'; import { useTagAPI } from '../../hooks/UseTagAPI'; import { useExploreProjectsQueryParams } from '../../hooks/UseProjectsQueryAPI'; diff --git a/frontend/src/components/projects/myProjectNav.js b/frontend/src/components/projects/myProjectNav.jsx similarity index 100% rename from frontend/src/components/projects/myProjectNav.js rename to frontend/src/components/projects/myProjectNav.jsx diff --git a/frontend/src/components/projects/orderBy.js b/frontend/src/components/projects/orderBy.jsx similarity index 100% rename from frontend/src/components/projects/orderBy.js rename to frontend/src/components/projects/orderBy.jsx diff --git a/frontend/src/components/projects/projectCardPaginator.js b/frontend/src/components/projects/projectCardPaginator.jsx similarity index 100% rename from frontend/src/components/projects/projectCardPaginator.js rename to frontend/src/components/projects/projectCardPaginator.jsx diff --git a/frontend/src/components/projects/projectNav.js b/frontend/src/components/projects/projectNav.jsx similarity index 100% rename from frontend/src/components/projects/projectNav.js rename to frontend/src/components/projects/projectNav.jsx diff --git a/frontend/src/components/projects/projectSearchBox.js b/frontend/src/components/projects/projectSearchBox.jsx similarity index 100% rename from frontend/src/components/projects/projectSearchBox.js rename to frontend/src/components/projects/projectSearchBox.jsx diff --git a/frontend/src/components/projects/projectSearchResults.js b/frontend/src/components/projects/projectSearchResults.jsx similarity index 100% rename from frontend/src/components/projects/projectSearchResults.js rename to frontend/src/components/projects/projectSearchResults.jsx diff --git a/frontend/src/components/projects/projectsActionFilter.js b/frontend/src/components/projects/projectsActionFilter.jsx similarity index 100% rename from frontend/src/components/projects/projectsActionFilter.js rename to frontend/src/components/projects/projectsActionFilter.jsx diff --git a/frontend/src/components/statsTimestamp/index.js b/frontend/src/components/statsTimestamp/index.jsx similarity index 100% rename from frontend/src/components/statsTimestamp/index.js rename to frontend/src/components/statsTimestamp/index.jsx diff --git a/frontend/src/components/statsTimestamp/messages.js b/frontend/src/components/statsTimestamp/messages.ts similarity index 100% rename from frontend/src/components/statsTimestamp/messages.js rename to frontend/src/components/statsTimestamp/messages.ts diff --git a/frontend/src/components/svgIcons/alert.js b/frontend/src/components/svgIcons/alert.js deleted file mode 100644 index 4085c6e251..0000000000 --- a/frontend/src/components/svgIcons/alert.js +++ /dev/null @@ -1,14 +0,0 @@ -import { PureComponent } from 'react'; - -export class AlertIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/alert.tsx b/frontend/src/components/svgIcons/alert.tsx new file mode 100644 index 0000000000..b2523853d4 --- /dev/null +++ b/frontend/src/components/svgIcons/alert.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from 'react'; + +export const AlertIcon = (props: HTMLProps) => { + return ( + + + + ); +} diff --git a/frontend/src/components/svgIcons/area.js b/frontend/src/components/svgIcons/area.js deleted file mode 100644 index df16345bd9..0000000000 --- a/frontend/src/components/svgIcons/area.js +++ /dev/null @@ -1,32 +0,0 @@ -import { PureComponent } from 'react'; - -export class AreaIcon extends PureComponent { - render() { - return ( - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/area.tsx b/frontend/src/components/svgIcons/area.tsx new file mode 100644 index 0000000000..f74378e390 --- /dev/null +++ b/frontend/src/components/svgIcons/area.tsx @@ -0,0 +1,28 @@ +import { HTMLProps } from 'react'; + +export const AreaIcon = (props: HTMLProps) => ( + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/asterisk.js b/frontend/src/components/svgIcons/asterisk.js deleted file mode 100644 index 5f8de49bc1..0000000000 --- a/frontend/src/components/svgIcons/asterisk.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class AsteriskIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/asterisk.tsx b/frontend/src/components/svgIcons/asterisk.tsx new file mode 100644 index 0000000000..3934ff1f95 --- /dev/null +++ b/frontend/src/components/svgIcons/asterisk.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from 'react'; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const AsteriskIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/ban.js b/frontend/src/components/svgIcons/ban.js deleted file mode 100644 index 0daa94515a..0000000000 --- a/frontend/src/components/svgIcons/ban.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class BanIcon extends PureComponent { - render() { - return ( - - ); - } -} diff --git a/frontend/src/components/svgIcons/ban.tsx b/frontend/src/components/svgIcons/ban.tsx new file mode 100644 index 0000000000..8d5a7d282b --- /dev/null +++ b/frontend/src/components/svgIcons/ban.tsx @@ -0,0 +1,12 @@ +import { HTMLProps, PureComponent } from 'react'; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const BanIcon = (props: HTMLProps) => ( + +); diff --git a/frontend/src/components/svgIcons/bell.js b/frontend/src/components/svgIcons/bell.js deleted file mode 100644 index c09df19c18..0000000000 --- a/frontend/src/components/svgIcons/bell.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -export class BellIcon extends PureComponent { - render() { - return ( - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/bell.tsx b/frontend/src/components/svgIcons/bell.tsx new file mode 100644 index 0000000000..72708b41cb --- /dev/null +++ b/frontend/src/components/svgIcons/bell.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from "react"; + +export const BellIcon = (props: HTMLProps) => ( + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/calendar.js b/frontend/src/components/svgIcons/calendar.js deleted file mode 100644 index a66725b5a7..0000000000 --- a/frontend/src/components/svgIcons/calendar.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class CalendarIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/calendar.tsx b/frontend/src/components/svgIcons/calendar.tsx new file mode 100644 index 0000000000..1728509c31 --- /dev/null +++ b/frontend/src/components/svgIcons/calendar.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from 'react'; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const CalendarIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/chart.js b/frontend/src/components/svgIcons/chart.js deleted file mode 100644 index 05fae045e3..0000000000 --- a/frontend/src/components/svgIcons/chart.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class ChartLineIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/chart.tsx b/frontend/src/components/svgIcons/chart.tsx new file mode 100644 index 0000000000..7a9b227e18 --- /dev/null +++ b/frontend/src/components/svgIcons/chart.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from 'react'; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const ChartLineIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/check.js b/frontend/src/components/svgIcons/check.js deleted file mode 100644 index e9fcdd1a43..0000000000 --- a/frontend/src/components/svgIcons/check.js +++ /dev/null @@ -1,15 +0,0 @@ -import { PureComponent } from 'react'; - -export class CheckIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/check.tsx b/frontend/src/components/svgIcons/check.tsx new file mode 100644 index 0000000000..6e18674c08 --- /dev/null +++ b/frontend/src/components/svgIcons/check.tsx @@ -0,0 +1,11 @@ +import { HTMLProps } from 'react'; + +export const CheckIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/chevron-down.js b/frontend/src/components/svgIcons/chevron-down.js deleted file mode 100644 index 21bd74b378..0000000000 --- a/frontend/src/components/svgIcons/chevron-down.js +++ /dev/null @@ -1,14 +0,0 @@ -import { PureComponent } from 'react'; - -export class ChevronDownIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/chevron-down.tsx b/frontend/src/components/svgIcons/chevron-down.tsx new file mode 100644 index 0000000000..00e8c5cb54 --- /dev/null +++ b/frontend/src/components/svgIcons/chevron-down.tsx @@ -0,0 +1,10 @@ +import { HTMLProps } from "react"; + +export const ChevronDownIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/chevron-right.js b/frontend/src/components/svgIcons/chevron-right.js deleted file mode 100644 index c75175cb04..0000000000 --- a/frontend/src/components/svgIcons/chevron-right.js +++ /dev/null @@ -1,14 +0,0 @@ -import { PureComponent } from 'react'; - -export class ChevronRightIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/chevron-right.tsx b/frontend/src/components/svgIcons/chevron-right.tsx new file mode 100644 index 0000000000..f9de898066 --- /dev/null +++ b/frontend/src/components/svgIcons/chevron-right.tsx @@ -0,0 +1,10 @@ +import { HTMLProps } from "react"; + +export const ChevronRightIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/chevron-up.js b/frontend/src/components/svgIcons/chevron-up.js deleted file mode 100644 index 850120d1c1..0000000000 --- a/frontend/src/components/svgIcons/chevron-up.js +++ /dev/null @@ -1,14 +0,0 @@ -import { PureComponent } from 'react'; - -export class ChevronUpIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/chevron-up.tsx b/frontend/src/components/svgIcons/chevron-up.tsx new file mode 100644 index 0000000000..eadf5aeecf --- /dev/null +++ b/frontend/src/components/svgIcons/chevron-up.tsx @@ -0,0 +1,10 @@ +import { HTMLProps } from "react"; + +export const ChevronUpIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/circle.js b/frontend/src/components/svgIcons/circle.js deleted file mode 100644 index c778c06b3c..0000000000 --- a/frontend/src/components/svgIcons/circle.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class CircleIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/circle.tsx b/frontend/src/components/svgIcons/circle.tsx new file mode 100644 index 0000000000..09132044d9 --- /dev/null +++ b/frontend/src/components/svgIcons/circle.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from "react"; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const CircleIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/circleExclamation.js b/frontend/src/components/svgIcons/circleExclamation.js deleted file mode 100644 index 4163d4fa03..0000000000 --- a/frontend/src/components/svgIcons/circleExclamation.js +++ /dev/null @@ -1,21 +0,0 @@ -import { PureComponent } from 'react'; - -export class CircleExclamationIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/circleExclamation.tsx b/frontend/src/components/svgIcons/circleExclamation.tsx new file mode 100644 index 0000000000..9e11301a55 --- /dev/null +++ b/frontend/src/components/svgIcons/circleExclamation.tsx @@ -0,0 +1,17 @@ +import { HTMLProps } from 'react'; + +export const CircleExclamationIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/circleMinus.js b/frontend/src/components/svgIcons/circleMinus.js deleted file mode 100644 index 51c67bb61a..0000000000 --- a/frontend/src/components/svgIcons/circleMinus.js +++ /dev/null @@ -1,21 +0,0 @@ -import { PureComponent } from 'react'; - -export class CircleMinusIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/circleMinus.tsx b/frontend/src/components/svgIcons/circleMinus.tsx new file mode 100644 index 0000000000..e752f28816 --- /dev/null +++ b/frontend/src/components/svgIcons/circleMinus.tsx @@ -0,0 +1,17 @@ +import { HTMLProps } from 'react'; + +export const CircleMinusIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/clipboard.js b/frontend/src/components/svgIcons/clipboard.js deleted file mode 100644 index 8c1e94d192..0000000000 --- a/frontend/src/components/svgIcons/clipboard.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class ClipboardIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/clipboard.tsx b/frontend/src/components/svgIcons/clipboard.tsx new file mode 100644 index 0000000000..b338f48aa3 --- /dev/null +++ b/frontend/src/components/svgIcons/clipboard.tsx @@ -0,0 +1,14 @@ + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ + +import { HTMLProps } from "react"; + +// License: CC-By 4.0 +export const ClipboardIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/clock.js b/frontend/src/components/svgIcons/clock.js deleted file mode 100644 index 9d0459913e..0000000000 --- a/frontend/src/components/svgIcons/clock.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class ClockIcon extends PureComponent { - render() { - return ( - - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/clock.tsx b/frontend/src/components/svgIcons/clock.tsx new file mode 100644 index 0000000000..23ea89f1fe --- /dev/null +++ b/frontend/src/components/svgIcons/clock.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from "react"; + +export const ClockIcon = (props: HTMLProps) => ( + + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/close.js b/frontend/src/components/svgIcons/close.js deleted file mode 100644 index d7122d4879..0000000000 --- a/frontend/src/components/svgIcons/close.js +++ /dev/null @@ -1,14 +0,0 @@ -import { PureComponent } from 'react'; - -export class CloseIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/close.tsx b/frontend/src/components/svgIcons/close.tsx new file mode 100644 index 0000000000..4732976c7e --- /dev/null +++ b/frontend/src/components/svgIcons/close.tsx @@ -0,0 +1,10 @@ +import { HTMLProps } from "react"; + +export const CloseIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/comment.js b/frontend/src/components/svgIcons/comment.js deleted file mode 100644 index 38ce263370..0000000000 --- a/frontend/src/components/svgIcons/comment.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class CommentIcon extends PureComponent { - render() { - return ( - - ); - } -} diff --git a/frontend/src/components/svgIcons/comment.tsx b/frontend/src/components/svgIcons/comment.tsx new file mode 100644 index 0000000000..35ccf9edf1 --- /dev/null +++ b/frontend/src/components/svgIcons/comment.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from "react"; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const CommentIcon = (props: HTMLProps) => ( + +); diff --git a/frontend/src/components/svgIcons/copyright.js b/frontend/src/components/svgIcons/copyright.js deleted file mode 100644 index 2ac5918e1f..0000000000 --- a/frontend/src/components/svgIcons/copyright.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class CopyrightIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/copyright.tsx b/frontend/src/components/svgIcons/copyright.tsx new file mode 100644 index 0000000000..8bcd0a12f9 --- /dev/null +++ b/frontend/src/components/svgIcons/copyright.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from 'react'; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const CopyrightIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/cut.js b/frontend/src/components/svgIcons/cut.js deleted file mode 100644 index 76b169340a..0000000000 --- a/frontend/src/components/svgIcons/cut.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class CutIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/cut.tsx b/frontend/src/components/svgIcons/cut.tsx new file mode 100644 index 0000000000..5acb011131 --- /dev/null +++ b/frontend/src/components/svgIcons/cut.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from "react"; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const CutIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/dataUse.js b/frontend/src/components/svgIcons/dataUse.js deleted file mode 100644 index 791ec18e4e..0000000000 --- a/frontend/src/components/svgIcons/dataUse.js +++ /dev/null @@ -1,24 +0,0 @@ -import { PureComponent } from 'react'; - -export class DataUseIcon extends PureComponent { - render() { - return ( - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/dataUse.tsx b/frontend/src/components/svgIcons/dataUse.tsx new file mode 100644 index 0000000000..5831072550 --- /dev/null +++ b/frontend/src/components/svgIcons/dataUse.tsx @@ -0,0 +1,20 @@ +import { HTMLProps } from "react"; + +export const DataUseIcon = (props: HTMLProps) => ( + + + + + + + +); diff --git a/frontend/src/components/svgIcons/disasterResponse.js b/frontend/src/components/svgIcons/disasterResponse.js deleted file mode 100644 index 7b0d141c03..0000000000 --- a/frontend/src/components/svgIcons/disasterResponse.js +++ /dev/null @@ -1,33 +0,0 @@ -import { PureComponent } from 'react'; - -export class DisasterResponseIcon extends PureComponent { - render() { - return ( - - - - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/disasterResponse.tsx b/frontend/src/components/svgIcons/disasterResponse.tsx new file mode 100644 index 0000000000..d851534536 --- /dev/null +++ b/frontend/src/components/svgIcons/disasterResponse.tsx @@ -0,0 +1,29 @@ +import { HTMLProps } from "react"; + +export const DisasterResponseIcon = (props: HTMLProps) => ( + + + + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/download.js b/frontend/src/components/svgIcons/download.js deleted file mode 100644 index 61d0399042..0000000000 --- a/frontend/src/components/svgIcons/download.js +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; - -export class DownloadIcon extends React.PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/download.tsx b/frontend/src/components/svgIcons/download.tsx new file mode 100644 index 0000000000..de1b76d74d --- /dev/null +++ b/frontend/src/components/svgIcons/download.tsx @@ -0,0 +1,17 @@ +import { HTMLProps } from "react"; + +export const DownloadIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/edit.js b/frontend/src/components/svgIcons/edit.js deleted file mode 100644 index 1c8b41e1c9..0000000000 --- a/frontend/src/components/svgIcons/edit.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class EditIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/edit.tsx b/frontend/src/components/svgIcons/edit.tsx new file mode 100644 index 0000000000..6d7e1f7c3c --- /dev/null +++ b/frontend/src/components/svgIcons/edit.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from "react"; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const EditIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/envelope.js b/frontend/src/components/svgIcons/envelope.js deleted file mode 100644 index 0772d4b0ae..0000000000 --- a/frontend/src/components/svgIcons/envelope.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class EnvelopeIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/envelope.tsx b/frontend/src/components/svgIcons/envelope.tsx new file mode 100644 index 0000000000..a85446cbc9 --- /dev/null +++ b/frontend/src/components/svgIcons/envelope.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from "react"; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const EnvelopeIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/exit.js b/frontend/src/components/svgIcons/exit.js deleted file mode 100644 index 7896c8cc8a..0000000000 --- a/frontend/src/components/svgIcons/exit.js +++ /dev/null @@ -1,14 +0,0 @@ -import { PureComponent } from 'react'; - -export class ExitIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/exit.tsx b/frontend/src/components/svgIcons/exit.tsx new file mode 100644 index 0000000000..bd3207a647 --- /dev/null +++ b/frontend/src/components/svgIcons/exit.tsx @@ -0,0 +1,10 @@ +import { HTMLProps } from "react"; + +export const ExitIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/eye.js b/frontend/src/components/svgIcons/eye.js deleted file mode 100644 index a3ffb40456..0000000000 --- a/frontend/src/components/svgIcons/eye.js +++ /dev/null @@ -1,15 +0,0 @@ -import { PureComponent } from 'react'; - -export class EyeIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/eye.tsx b/frontend/src/components/svgIcons/eye.tsx new file mode 100644 index 0000000000..078a099e8d --- /dev/null +++ b/frontend/src/components/svgIcons/eye.tsx @@ -0,0 +1,11 @@ +import { HTMLProps } from "react"; + +export const EyeIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/facebook.js b/frontend/src/components/svgIcons/facebook.js deleted file mode 100644 index c5be8edb37..0000000000 --- a/frontend/src/components/svgIcons/facebook.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class FacebookIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/facebook.tsx b/frontend/src/components/svgIcons/facebook.tsx new file mode 100644 index 0000000000..5b21b21a33 --- /dev/null +++ b/frontend/src/components/svgIcons/facebook.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from "react"; + +export const FacebookIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/fileImport.js b/frontend/src/components/svgIcons/fileImport.js deleted file mode 100644 index bb4413e205..0000000000 --- a/frontend/src/components/svgIcons/fileImport.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class FileImportIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/fileImport.tsx b/frontend/src/components/svgIcons/fileImport.tsx new file mode 100644 index 0000000000..684ebeb6a1 --- /dev/null +++ b/frontend/src/components/svgIcons/fileImport.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from "react"; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const FileImportIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/flag.js b/frontend/src/components/svgIcons/flag.js deleted file mode 100644 index bd99a94af7..0000000000 --- a/frontend/src/components/svgIcons/flag.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class FlagIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/flag.tsx b/frontend/src/components/svgIcons/flag.tsx new file mode 100644 index 0000000000..fa44754a97 --- /dev/null +++ b/frontend/src/components/svgIcons/flag.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from "react"; + +export const FlagIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/github.js b/frontend/src/components/svgIcons/github.js deleted file mode 100644 index 414e6405ca..0000000000 --- a/frontend/src/components/svgIcons/github.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class GithubIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/github.tsx b/frontend/src/components/svgIcons/github.tsx new file mode 100644 index 0000000000..378fdd3aa9 --- /dev/null +++ b/frontend/src/components/svgIcons/github.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from "react"; + +export const GithubIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/grid.js b/frontend/src/components/svgIcons/grid.js deleted file mode 100644 index d22e1324bb..0000000000 --- a/frontend/src/components/svgIcons/grid.js +++ /dev/null @@ -1,31 +0,0 @@ -import { PureComponent } from 'react'; - -// Icons produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 - -export class FourCellsGridIcon extends PureComponent { - render() { - return ( - - - - ); - } -} - -export class NineCellsGridIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/grid.tsx b/frontend/src/components/svgIcons/grid.tsx new file mode 100644 index 0000000000..693f81ebd5 --- /dev/null +++ b/frontend/src/components/svgIcons/grid.tsx @@ -0,0 +1,22 @@ +import { HTMLProps } from "react"; + +// Icons produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const FourCellsGridIcon = (props: HTMLProps) => ( + + + +); + +export const NineCellsGridIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/grip.js b/frontend/src/components/svgIcons/grip.js deleted file mode 100644 index 18b8784f3b..0000000000 --- a/frontend/src/components/svgIcons/grip.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class GripIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/grip.tsx b/frontend/src/components/svgIcons/grip.tsx new file mode 100644 index 0000000000..b114edc1ad --- /dev/null +++ b/frontend/src/components/svgIcons/grip.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from "react"; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const GripIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/hashtag.js b/frontend/src/components/svgIcons/hashtag.js deleted file mode 100644 index 60dd5710b6..0000000000 --- a/frontend/src/components/svgIcons/hashtag.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class HashtagIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/hashtag.tsx b/frontend/src/components/svgIcons/hashtag.tsx new file mode 100644 index 0000000000..87914e2275 --- /dev/null +++ b/frontend/src/components/svgIcons/hashtag.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from "react"; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const HashtagIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/health.js b/frontend/src/components/svgIcons/health.js deleted file mode 100644 index f213211a98..0000000000 --- a/frontend/src/components/svgIcons/health.js +++ /dev/null @@ -1,26 +0,0 @@ -import { PureComponent } from 'react'; - -export class HealthIcon extends PureComponent { - render() { - return ( - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/health.tsx b/frontend/src/components/svgIcons/health.tsx new file mode 100644 index 0000000000..17e6b73721 --- /dev/null +++ b/frontend/src/components/svgIcons/health.tsx @@ -0,0 +1,22 @@ +import { HTMLProps } from "react"; + +export const HealthIcon = (props: HTMLProps) => ( + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/home.js b/frontend/src/components/svgIcons/home.js deleted file mode 100644 index 1518aa9c72..0000000000 --- a/frontend/src/components/svgIcons/home.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class HomeIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/home.tsx b/frontend/src/components/svgIcons/home.tsx new file mode 100644 index 0000000000..a3a6ae8a28 --- /dev/null +++ b/frontend/src/components/svgIcons/home.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from "react"; + +export const HomeIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/humanProcessing.js b/frontend/src/components/svgIcons/humanProcessing.js deleted file mode 100644 index 8d3fb26799..0000000000 --- a/frontend/src/components/svgIcons/humanProcessing.js +++ /dev/null @@ -1,58 +0,0 @@ -import { PureComponent } from 'react'; - -export class HumanProcessingIcon extends PureComponent { - render() { - return ( - - - - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/humanProcessing.tsx b/frontend/src/components/svgIcons/humanProcessing.tsx new file mode 100644 index 0000000000..be9e2286bb --- /dev/null +++ b/frontend/src/components/svgIcons/humanProcessing.tsx @@ -0,0 +1,54 @@ +import { HTMLProps } from 'react'; + +export const HumanProcessingIcon = (props: HTMLProps) => ( + + + + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/index.js b/frontend/src/components/svgIcons/index.ts similarity index 100% rename from frontend/src/components/svgIcons/index.js rename to frontend/src/components/svgIcons/index.ts diff --git a/frontend/src/components/svgIcons/info.js b/frontend/src/components/svgIcons/info.js deleted file mode 100644 index 7853450b73..0000000000 --- a/frontend/src/components/svgIcons/info.js +++ /dev/null @@ -1,14 +0,0 @@ -import { PureComponent } from 'react'; - -export class InfoIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/info.tsx b/frontend/src/components/svgIcons/info.tsx new file mode 100644 index 0000000000..98aa62e388 --- /dev/null +++ b/frontend/src/components/svgIcons/info.tsx @@ -0,0 +1,10 @@ +import { HTMLProps } from 'react'; + +export const InfoIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/instagram.js b/frontend/src/components/svgIcons/instagram.js deleted file mode 100644 index 1cf654f5b4..0000000000 --- a/frontend/src/components/svgIcons/instagram.js +++ /dev/null @@ -1,23 +0,0 @@ -import { PureComponent } from 'react'; - -export class InstagramIcon extends PureComponent { - render() { - return ( - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/instagram.tsx b/frontend/src/components/svgIcons/instagram.tsx new file mode 100644 index 0000000000..5c8907c077 --- /dev/null +++ b/frontend/src/components/svgIcons/instagram.tsx @@ -0,0 +1,19 @@ +import { HTMLProps } from 'react'; + +export const InstagramIcon = (props: HTMLProps) => ( + + + + + + + +); diff --git a/frontend/src/components/svgIcons/invalidated.js b/frontend/src/components/svgIcons/invalidated.js deleted file mode 100644 index e76992c8eb..0000000000 --- a/frontend/src/components/svgIcons/invalidated.js +++ /dev/null @@ -1,17 +0,0 @@ -import { PureComponent } from 'react'; - -export class InvalidatedIcon extends PureComponent { - render() { - return ( - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/invalidated.tsx b/frontend/src/components/svgIcons/invalidated.tsx new file mode 100644 index 0000000000..1ece405ef1 --- /dev/null +++ b/frontend/src/components/svgIcons/invalidated.tsx @@ -0,0 +1,13 @@ +import { HTMLProps } from 'react'; + +export const InvalidatedIcon = (props: HTMLProps) => ( + + + + + +); diff --git a/frontend/src/components/svgIcons/left.js b/frontend/src/components/svgIcons/left.js deleted file mode 100644 index f15c72fce7..0000000000 --- a/frontend/src/components/svgIcons/left.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class LeftIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/left.tsx b/frontend/src/components/svgIcons/left.tsx new file mode 100644 index 0000000000..11abb93e2d --- /dev/null +++ b/frontend/src/components/svgIcons/left.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from "react"; + +export const LeftIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/link.js b/frontend/src/components/svgIcons/link.js deleted file mode 100644 index 070059d3e9..0000000000 --- a/frontend/src/components/svgIcons/link.js +++ /dev/null @@ -1,29 +0,0 @@ -import { PureComponent } from 'react'; - -export class ExternalLinkIcon extends PureComponent { - render() { - return ( - - - - ); - } -} - -export class InternalLinkIcon extends PureComponent { - // Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ - // License: CC-By 4.0 - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/link.tsx b/frontend/src/components/svgIcons/link.tsx new file mode 100644 index 0000000000..c51dd1d5d9 --- /dev/null +++ b/frontend/src/components/svgIcons/link.tsx @@ -0,0 +1,21 @@ +import { HTMLProps } from "react"; + +export const ExternalLinkIcon = (props: HTMLProps) => ( + + + +); + +export const InternalLinkIcon = (props: HTMLProps) => ( + // Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ + // License: CC-By 4.0 + + + +); diff --git a/frontend/src/components/svgIcons/linkedin.js b/frontend/src/components/svgIcons/linkedin.js deleted file mode 100644 index dab9b14021..0000000000 --- a/frontend/src/components/svgIcons/linkedin.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class LinkedinIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/linkedin.tsx b/frontend/src/components/svgIcons/linkedin.tsx new file mode 100644 index 0000000000..dd4a1c1976 --- /dev/null +++ b/frontend/src/components/svgIcons/linkedin.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from 'react'; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const LinkedinIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/list.js b/frontend/src/components/svgIcons/list.js deleted file mode 100644 index c021484125..0000000000 --- a/frontend/src/components/svgIcons/list.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class ListIcon extends PureComponent { - render() { - return ( - - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/list.tsx b/frontend/src/components/svgIcons/list.tsx new file mode 100644 index 0000000000..67c58b6db8 --- /dev/null +++ b/frontend/src/components/svgIcons/list.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from 'react'; + +export const ListIcon = (props: HTMLProps) => ( + + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/loading.js b/frontend/src/components/svgIcons/loading.js deleted file mode 100644 index 3a28a9afae..0000000000 --- a/frontend/src/components/svgIcons/loading.js +++ /dev/null @@ -1,14 +0,0 @@ -import { PureComponent } from 'react'; - -export class LoadingIcon extends PureComponent { - render() { - return ( - - ); - } -} diff --git a/frontend/src/components/svgIcons/loading.tsx b/frontend/src/components/svgIcons/loading.tsx new file mode 100644 index 0000000000..a9d22644bf --- /dev/null +++ b/frontend/src/components/svgIcons/loading.tsx @@ -0,0 +1,10 @@ +import { HTMLProps } from 'react'; + +export const LoadingIcon = (props: HTMLProps) => ( + +); diff --git a/frontend/src/components/svgIcons/lock.js b/frontend/src/components/svgIcons/lock.js deleted file mode 100644 index 4a531a0c1b..0000000000 --- a/frontend/src/components/svgIcons/lock.js +++ /dev/null @@ -1,15 +0,0 @@ -import { PureComponent } from 'react'; - -export class LockIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/lock.tsx b/frontend/src/components/svgIcons/lock.tsx new file mode 100644 index 0000000000..5f4d717cee --- /dev/null +++ b/frontend/src/components/svgIcons/lock.tsx @@ -0,0 +1,11 @@ +import { HTMLProps } from "react"; + +export const LockIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/manage.js b/frontend/src/components/svgIcons/manage.js deleted file mode 100644 index be01874822..0000000000 --- a/frontend/src/components/svgIcons/manage.js +++ /dev/null @@ -1,46 +0,0 @@ -import { PureComponent } from 'react'; - -export class ManageIcon extends PureComponent { - render() { - return ( - - - - - - - - - - ); - } -} - -export class GearIcon extends PureComponent { - render() { - return ( - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/manage.tsx b/frontend/src/components/svgIcons/manage.tsx new file mode 100644 index 0000000000..910f9a6373 --- /dev/null +++ b/frontend/src/components/svgIcons/manage.tsx @@ -0,0 +1,38 @@ +import { HTMLProps } from 'react'; + +export const ManageIcon = (props: HTMLProps) => ( + + + + + + + + + +); + +export const GearIcon = (props: HTMLProps) => ( + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/map.js b/frontend/src/components/svgIcons/map.js deleted file mode 100644 index dfd1bdb1bc..0000000000 --- a/frontend/src/components/svgIcons/map.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class MapIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/map.tsx b/frontend/src/components/svgIcons/map.tsx new file mode 100644 index 0000000000..3f1424d69d --- /dev/null +++ b/frontend/src/components/svgIcons/map.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from 'react'; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const MapIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/mapped.js b/frontend/src/components/svgIcons/mapped.js deleted file mode 100644 index 0177ac226d..0000000000 --- a/frontend/src/components/svgIcons/mapped.js +++ /dev/null @@ -1,52 +0,0 @@ -import { PureComponent } from 'react'; - -export class MappedIcon extends PureComponent { - render() { - return ( - - - - - - - - - - - - - - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/mapped.tsx b/frontend/src/components/svgIcons/mapped.tsx new file mode 100644 index 0000000000..ad9386ca4f --- /dev/null +++ b/frontend/src/components/svgIcons/mapped.tsx @@ -0,0 +1,48 @@ +import { HTMLProps } from 'react'; + +export const MappedIcon = (props: HTMLProps) => ( + + + + + + + + + + + + + + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/mappedSquare.js b/frontend/src/components/svgIcons/mappedSquare.js deleted file mode 100644 index f9e060e1ad..0000000000 --- a/frontend/src/components/svgIcons/mappedSquare.js +++ /dev/null @@ -1,73 +0,0 @@ -import { PureComponent } from 'react'; - -export class MappedSquareIcon extends PureComponent { - render() { - return ( - - - - - - - - - - - - - - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/mappedSquare.tsx b/frontend/src/components/svgIcons/mappedSquare.tsx new file mode 100644 index 0000000000..5d6bbfacbc --- /dev/null +++ b/frontend/src/components/svgIcons/mappedSquare.tsx @@ -0,0 +1,69 @@ +import { HTMLProps } from 'react'; + +export const MappedSquareIcon = (props: HTMLProps) => ( + + + + + + + + + + + + + + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/mapping.js b/frontend/src/components/svgIcons/mapping.js deleted file mode 100644 index 1a24961ac7..0000000000 --- a/frontend/src/components/svgIcons/mapping.js +++ /dev/null @@ -1,31 +0,0 @@ -import { PureComponent } from 'react'; - -export class MappingIcon extends PureComponent { - render() { - return ( - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/mapping.tsx b/frontend/src/components/svgIcons/mapping.tsx new file mode 100644 index 0000000000..b8b3fe9608 --- /dev/null +++ b/frontend/src/components/svgIcons/mapping.tsx @@ -0,0 +1,27 @@ +import { HTMLProps } from 'react'; + +export const MappingIcon = (props: HTMLProps) => ( + + + + + + + +); diff --git a/frontend/src/components/svgIcons/marker.js b/frontend/src/components/svgIcons/marker.js deleted file mode 100644 index 7df91944a6..0000000000 --- a/frontend/src/components/svgIcons/marker.js +++ /dev/null @@ -1,14 +0,0 @@ -import { PureComponent } from 'react'; - -export class MarkerIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/marker.tsx b/frontend/src/components/svgIcons/marker.tsx new file mode 100644 index 0000000000..c462463665 --- /dev/null +++ b/frontend/src/components/svgIcons/marker.tsx @@ -0,0 +1,10 @@ +import { HTMLProps } from 'react'; + +export const MarkerIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/menu.js b/frontend/src/components/svgIcons/menu.js deleted file mode 100644 index 821f584d17..0000000000 --- a/frontend/src/components/svgIcons/menu.js +++ /dev/null @@ -1,15 +0,0 @@ -import { PureComponent } from 'react'; - -export class MenuIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/menu.tsx b/frontend/src/components/svgIcons/menu.tsx new file mode 100644 index 0000000000..4d7f6bd0be --- /dev/null +++ b/frontend/src/components/svgIcons/menu.tsx @@ -0,0 +1,11 @@ +import { HTMLProps } from 'react'; + +export const MenuIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/pencil.js b/frontend/src/components/svgIcons/pencil.js deleted file mode 100644 index 5357ba5dc1..0000000000 --- a/frontend/src/components/svgIcons/pencil.js +++ /dev/null @@ -1,15 +0,0 @@ -import { PureComponent } from 'react'; - -export class PencilIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/pencil.tsx b/frontend/src/components/svgIcons/pencil.tsx new file mode 100644 index 0000000000..65a3875eb2 --- /dev/null +++ b/frontend/src/components/svgIcons/pencil.tsx @@ -0,0 +1,11 @@ +import { HTMLProps } from 'react'; + +export const PencilIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/play.js b/frontend/src/components/svgIcons/play.js deleted file mode 100644 index 46ed3700ff..0000000000 --- a/frontend/src/components/svgIcons/play.js +++ /dev/null @@ -1,14 +0,0 @@ -import { PureComponent } from 'react'; - -export class PlayIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/play.tsx b/frontend/src/components/svgIcons/play.tsx new file mode 100644 index 0000000000..f0bb13c03f --- /dev/null +++ b/frontend/src/components/svgIcons/play.tsx @@ -0,0 +1,10 @@ +import { HTMLProps } from "react"; + +export const PlayIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/plus.js b/frontend/src/components/svgIcons/plus.js deleted file mode 100644 index a0176a707f..0000000000 --- a/frontend/src/components/svgIcons/plus.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class PlusIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/plus.tsx b/frontend/src/components/svgIcons/plus.tsx new file mode 100644 index 0000000000..0333d35f57 --- /dev/null +++ b/frontend/src/components/svgIcons/plus.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from 'react'; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const PlusIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/polygon.js b/frontend/src/components/svgIcons/polygon.js deleted file mode 100644 index f6877e5b29..0000000000 --- a/frontend/src/components/svgIcons/polygon.js +++ /dev/null @@ -1,54 +0,0 @@ -import { PureComponent } from 'react'; - -export class PolygonIcon extends PureComponent { - render() { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/polygon.tsx b/frontend/src/components/svgIcons/polygon.tsx new file mode 100644 index 0000000000..c32e4d7612 --- /dev/null +++ b/frontend/src/components/svgIcons/polygon.tsx @@ -0,0 +1,50 @@ +import { HTMLProps } from 'react'; + +export const PolygonIcon = (props: HTMLProps) => ( + + + + + + + + + + + + + + + + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/profilePicture.js b/frontend/src/components/svgIcons/profilePicture.js deleted file mode 100644 index 9b29941f20..0000000000 --- a/frontend/src/components/svgIcons/profilePicture.js +++ /dev/null @@ -1,71 +0,0 @@ -import { PureComponent } from 'react'; - -export class ProfilePictureIcon extends PureComponent { - render() { - return ( - - - - - - ); - } -} - -export class UserIcon extends PureComponent { - render() { - return ( - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/profilePicture.tsx b/frontend/src/components/svgIcons/profilePicture.tsx new file mode 100644 index 0000000000..47e50ef85e --- /dev/null +++ b/frontend/src/components/svgIcons/profilePicture.tsx @@ -0,0 +1,63 @@ +import { HTMLProps } from 'react'; + +export const ProfilePictureIcon = (props: HTMLProps) => ( + + + + + +); + +export const UserIcon = (props: HTMLProps) => ( + + + + +); diff --git a/frontend/src/components/svgIcons/projectSelection.js b/frontend/src/components/svgIcons/projectSelection.js deleted file mode 100644 index 6b0efc9f96..0000000000 --- a/frontend/src/components/svgIcons/projectSelection.js +++ /dev/null @@ -1,22 +0,0 @@ -import { PureComponent } from 'react'; - -export class ProjectSelectionIcon extends PureComponent { - render() { - return ( - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/projectSelection.tsx b/frontend/src/components/svgIcons/projectSelection.tsx new file mode 100644 index 0000000000..2318868c65 --- /dev/null +++ b/frontend/src/components/svgIcons/projectSelection.tsx @@ -0,0 +1,18 @@ +import { HTMLProps } from 'react'; + +export const ProjectSelectionIcon = (props: HTMLProps) => ( + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/questionCircle.js b/frontend/src/components/svgIcons/questionCircle.js deleted file mode 100644 index a775cb612c..0000000000 --- a/frontend/src/components/svgIcons/questionCircle.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class QuestionCircleIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/questionCircle.tsx b/frontend/src/components/svgIcons/questionCircle.tsx new file mode 100644 index 0000000000..ead29557d5 --- /dev/null +++ b/frontend/src/components/svgIcons/questionCircle.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from 'react'; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const QuestionCircleIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/refresh.js b/frontend/src/components/svgIcons/refresh.js deleted file mode 100644 index 3e35b8b9b0..0000000000 --- a/frontend/src/components/svgIcons/refresh.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class RefreshIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/refresh.tsx b/frontend/src/components/svgIcons/refresh.tsx new file mode 100644 index 0000000000..74bc9ba443 --- /dev/null +++ b/frontend/src/components/svgIcons/refresh.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from 'react'; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const RefreshIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/refugeeResponse.js b/frontend/src/components/svgIcons/refugeeResponse.js deleted file mode 100644 index 1167f6c562..0000000000 --- a/frontend/src/components/svgIcons/refugeeResponse.js +++ /dev/null @@ -1,31 +0,0 @@ -import { PureComponent } from 'react'; - -export class RefugeeResponseIcon extends PureComponent { - render() { - return ( - - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/refugeeResponse.tsx b/frontend/src/components/svgIcons/refugeeResponse.tsx new file mode 100644 index 0000000000..9db5682e66 --- /dev/null +++ b/frontend/src/components/svgIcons/refugeeResponse.tsx @@ -0,0 +1,27 @@ +import { HTMLProps } from 'react'; + +export const RefugeeResponseIcon = (props: HTMLProps) => ( + + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/resume.js b/frontend/src/components/svgIcons/resume.js deleted file mode 100644 index 77be64bbbc..0000000000 --- a/frontend/src/components/svgIcons/resume.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class ResumeIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/resume.tsx b/frontend/src/components/svgIcons/resume.tsx new file mode 100644 index 0000000000..732108cd40 --- /dev/null +++ b/frontend/src/components/svgIcons/resume.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from "react"; + +export const ResumeIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/right.js b/frontend/src/components/svgIcons/right.js deleted file mode 100644 index cd53ed9917..0000000000 --- a/frontend/src/components/svgIcons/right.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class RightIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/right.tsx b/frontend/src/components/svgIcons/right.tsx new file mode 100644 index 0000000000..fb6420908d --- /dev/null +++ b/frontend/src/components/svgIcons/right.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from "react"; + +export const RightIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/road.js b/frontend/src/components/svgIcons/road.js deleted file mode 100644 index c403900a23..0000000000 --- a/frontend/src/components/svgIcons/road.js +++ /dev/null @@ -1,23 +0,0 @@ -import { PureComponent } from 'react'; - -export class RoadIcon extends PureComponent { - render() { - return ( - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/road.tsx b/frontend/src/components/svgIcons/road.tsx new file mode 100644 index 0000000000..00f8a6d9ed --- /dev/null +++ b/frontend/src/components/svgIcons/road.tsx @@ -0,0 +1,19 @@ +import { HTMLProps } from "react"; + +export const RoadIcon = (props: HTMLProps) => ( + + + + + + + +); diff --git a/frontend/src/components/svgIcons/search.js b/frontend/src/components/svgIcons/search.js deleted file mode 100644 index d46b8d87db..0000000000 --- a/frontend/src/components/svgIcons/search.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class SearchIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/search.tsx b/frontend/src/components/svgIcons/search.tsx new file mode 100644 index 0000000000..3d49066a29 --- /dev/null +++ b/frontend/src/components/svgIcons/search.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from 'react'; + +export const SearchIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/selectProject.js b/frontend/src/components/svgIcons/selectProject.js deleted file mode 100644 index 9e56c87593..0000000000 --- a/frontend/src/components/svgIcons/selectProject.js +++ /dev/null @@ -1,31 +0,0 @@ -import { PureComponent } from 'react'; - -export class SelectProject extends PureComponent { - render() { - return ( - - - - - - - - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/selectProject.tsx b/frontend/src/components/svgIcons/selectProject.tsx new file mode 100644 index 0000000000..ece993adde --- /dev/null +++ b/frontend/src/components/svgIcons/selectProject.tsx @@ -0,0 +1,27 @@ +import { HTMLProps } from "react"; + +export const SelectProject = (props: HTMLProps) => ( + + + + + + + + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/selectTask.js b/frontend/src/components/svgIcons/selectTask.js deleted file mode 100644 index 5703bda722..0000000000 --- a/frontend/src/components/svgIcons/selectTask.js +++ /dev/null @@ -1,33 +0,0 @@ -import { PureComponent } from 'react'; - -export class SelectTask extends PureComponent { - render() { - return ( - - - - - - - - - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/selectTask.tsx b/frontend/src/components/svgIcons/selectTask.tsx new file mode 100644 index 0000000000..15ed36789c --- /dev/null +++ b/frontend/src/components/svgIcons/selectTask.tsx @@ -0,0 +1,29 @@ +import { HTMLProps } from "react"; + +export const SelectTask = (props: HTMLProps) => ( + + + + + + + + + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/settings.js b/frontend/src/components/svgIcons/settings.js deleted file mode 100644 index 326deb65ff..0000000000 --- a/frontend/src/components/svgIcons/settings.js +++ /dev/null @@ -1,15 +0,0 @@ -import { PureComponent } from 'react'; - -export class SettingsIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/settings.tsx b/frontend/src/components/svgIcons/settings.tsx new file mode 100644 index 0000000000..a1aaebdd5d --- /dev/null +++ b/frontend/src/components/svgIcons/settings.tsx @@ -0,0 +1,11 @@ +import { HTMLProps } from "react"; + +export const SettingsIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/share.js b/frontend/src/components/svgIcons/share.js deleted file mode 100644 index d6a2da83d5..0000000000 --- a/frontend/src/components/svgIcons/share.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class ShareIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/share.tsx b/frontend/src/components/svgIcons/share.tsx new file mode 100644 index 0000000000..dfa8ef92ec --- /dev/null +++ b/frontend/src/components/svgIcons/share.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from "react"; + +export const ShareIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/sidebar.js b/frontend/src/components/svgIcons/sidebar.js deleted file mode 100644 index 0a911f0eef..0000000000 --- a/frontend/src/components/svgIcons/sidebar.js +++ /dev/null @@ -1,14 +0,0 @@ -import { PureComponent } from 'react'; - -export class SidebarIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/sidebar.tsx b/frontend/src/components/svgIcons/sidebar.tsx new file mode 100644 index 0000000000..e7fbedd105 --- /dev/null +++ b/frontend/src/components/svgIcons/sidebar.tsx @@ -0,0 +1,10 @@ +import { HTMLProps } from 'react'; + +export const SidebarIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/star.js b/frontend/src/components/svgIcons/star.js deleted file mode 100644 index 4c68e128cd..0000000000 --- a/frontend/src/components/svgIcons/star.js +++ /dev/null @@ -1,42 +0,0 @@ -import { PureComponent } from 'react'; - -// Icons produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class FullStarIcon extends PureComponent { - render() { - return ( - - - - ); - } -} - -export class StarIcon extends PureComponent { - render() { - return ( - - - - ); - } -} - -export class HalfStarIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/star.tsx b/frontend/src/components/svgIcons/star.tsx new file mode 100644 index 0000000000..cca215e878 --- /dev/null +++ b/frontend/src/components/svgIcons/star.tsx @@ -0,0 +1,30 @@ +import { HTMLProps } from "react"; + +// Icons produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const FullStarIcon = (props: HTMLProps) => ( + + + +); + +export const StarIcon = (props: HTMLProps) => ( + + + +); + +export const HalfStarIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/submitWork.js b/frontend/src/components/svgIcons/submitWork.js deleted file mode 100644 index ab94858ea5..0000000000 --- a/frontend/src/components/svgIcons/submitWork.js +++ /dev/null @@ -1,21 +0,0 @@ -import { PureComponent } from 'react'; - -export class SubmitWorkIcon extends PureComponent { - render() { - return ( - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/submitWork.tsx b/frontend/src/components/svgIcons/submitWork.tsx new file mode 100644 index 0000000000..7d065ba20d --- /dev/null +++ b/frontend/src/components/svgIcons/submitWork.tsx @@ -0,0 +1,17 @@ +import { HTMLProps } from 'react'; + +export const SubmitWorkIcon = (props: HTMLProps) => ( + + + + + + + +); diff --git a/frontend/src/components/svgIcons/task.js b/frontend/src/components/svgIcons/task.js deleted file mode 100644 index 865cdd8b83..0000000000 --- a/frontend/src/components/svgIcons/task.js +++ /dev/null @@ -1,17 +0,0 @@ -import { PureComponent } from 'react'; - -export class TaskIcon extends PureComponent { - render() { - return ( - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/task.tsx b/frontend/src/components/svgIcons/task.tsx new file mode 100644 index 0000000000..6933da91b9 --- /dev/null +++ b/frontend/src/components/svgIcons/task.tsx @@ -0,0 +1,13 @@ +import { HTMLProps } from "react"; + +export const TaskIcon = (props: HTMLProps) => ( + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/taskSelection.js b/frontend/src/components/svgIcons/taskSelection.js deleted file mode 100644 index 833af1d386..0000000000 --- a/frontend/src/components/svgIcons/taskSelection.js +++ /dev/null @@ -1,25 +0,0 @@ -import { PureComponent } from 'react'; - -export class TaskSelectionIcon extends PureComponent { - render() { - return ( - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/taskSelection.tsx b/frontend/src/components/svgIcons/taskSelection.tsx new file mode 100644 index 0000000000..e5c15942e7 --- /dev/null +++ b/frontend/src/components/svgIcons/taskSelection.tsx @@ -0,0 +1,21 @@ +import { HTMLProps } from 'react'; + +export const TaskSelectionIcon = (props: HTMLProps) => ( + + + + + + + +); diff --git a/frontend/src/components/svgIcons/timer.js b/frontend/src/components/svgIcons/timer.js deleted file mode 100644 index 517d368adf..0000000000 --- a/frontend/src/components/svgIcons/timer.js +++ /dev/null @@ -1,25 +0,0 @@ -import { PureComponent } from 'react'; - -export class TimerIcon extends PureComponent { - render() { - return ( - - Timer - - - ); - } -} diff --git a/frontend/src/components/svgIcons/timer.tsx b/frontend/src/components/svgIcons/timer.tsx new file mode 100644 index 0000000000..5f02fb957c --- /dev/null +++ b/frontend/src/components/svgIcons/timer.tsx @@ -0,0 +1,21 @@ +import { HTMLProps } from 'react'; + +export const TimerIcon = (props: HTMLProps) => ( + + Timer + + +); diff --git a/frontend/src/components/svgIcons/twitter.js b/frontend/src/components/svgIcons/twitter.js deleted file mode 100644 index 19ff3efaf1..0000000000 --- a/frontend/src/components/svgIcons/twitter.js +++ /dev/null @@ -1,23 +0,0 @@ -import { PureComponent } from 'react'; - -export class TwitterIcon extends PureComponent { - render() { - return ( - - {!this.props.noBg && } - - - ); - } -} diff --git a/frontend/src/components/svgIcons/twitter.tsx b/frontend/src/components/svgIcons/twitter.tsx new file mode 100644 index 0000000000..49086e50a4 --- /dev/null +++ b/frontend/src/components/svgIcons/twitter.tsx @@ -0,0 +1,25 @@ +import { HTMLProps } from 'react'; + +export const TwitterIcon = (props: HTMLProps & { + noBg?: boolean; +}) => { + const { noBg, ...rest } = props; + + return ( + + {!props.noBg && } + + + ) +} diff --git a/frontend/src/components/svgIcons/undo.js b/frontend/src/components/svgIcons/undo.js deleted file mode 100644 index ee52ad6890..0000000000 --- a/frontend/src/components/svgIcons/undo.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class UndoIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/undo.tsx b/frontend/src/components/svgIcons/undo.tsx new file mode 100644 index 0000000000..5cc7a45c20 --- /dev/null +++ b/frontend/src/components/svgIcons/undo.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from 'react'; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const UndoIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/svgIcons/validated.js b/frontend/src/components/svgIcons/validated.js deleted file mode 100644 index bafb4964cf..0000000000 --- a/frontend/src/components/svgIcons/validated.js +++ /dev/null @@ -1,17 +0,0 @@ -import { PureComponent } from 'react'; - -export class ValidatedIcon extends PureComponent { - render() { - return ( - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/validated.tsx b/frontend/src/components/svgIcons/validated.tsx new file mode 100644 index 0000000000..c35e297483 --- /dev/null +++ b/frontend/src/components/svgIcons/validated.tsx @@ -0,0 +1,13 @@ +import { HTMLProps } from 'react'; + +export const ValidatedIcon = (props: HTMLProps) => ( + + + + + +); diff --git a/frontend/src/components/svgIcons/validation.js b/frontend/src/components/svgIcons/validation.js deleted file mode 100644 index 7d3312ed01..0000000000 --- a/frontend/src/components/svgIcons/validation.js +++ /dev/null @@ -1,32 +0,0 @@ -import { PureComponent } from 'react'; - -export class ValidationIcon extends PureComponent { - render() { - return ( - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/validation.tsx b/frontend/src/components/svgIcons/validation.tsx new file mode 100644 index 0000000000..7932ed92ce --- /dev/null +++ b/frontend/src/components/svgIcons/validation.tsx @@ -0,0 +1,28 @@ +import { HTMLProps } from 'react'; + +export const ValidationIcon = (props: HTMLProps) => ( + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/view.js b/frontend/src/components/svgIcons/view.js deleted file mode 100644 index ef2ac16528..0000000000 --- a/frontend/src/components/svgIcons/view.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class ViewIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/view.tsx b/frontend/src/components/svgIcons/view.tsx new file mode 100644 index 0000000000..d36210cd0d --- /dev/null +++ b/frontend/src/components/svgIcons/view.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from "react"; + +export const ViewIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/waste.js b/frontend/src/components/svgIcons/waste.js deleted file mode 100644 index 62e075193a..0000000000 --- a/frontend/src/components/svgIcons/waste.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class WasteIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/waste.tsx b/frontend/src/components/svgIcons/waste.tsx new file mode 100644 index 0000000000..c6ab05e19c --- /dev/null +++ b/frontend/src/components/svgIcons/waste.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from "react"; + +export const WasteIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/waterSanitation.js b/frontend/src/components/svgIcons/waterSanitation.js deleted file mode 100644 index 305ccfac5d..0000000000 --- a/frontend/src/components/svgIcons/waterSanitation.js +++ /dev/null @@ -1,28 +0,0 @@ -import { PureComponent } from 'react'; - -export class WaterSanitationIcon extends PureComponent { - render() { - return ( - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/waterSanitation.tsx b/frontend/src/components/svgIcons/waterSanitation.tsx new file mode 100644 index 0000000000..b636236f02 --- /dev/null +++ b/frontend/src/components/svgIcons/waterSanitation.tsx @@ -0,0 +1,24 @@ +import { HTMLProps } from 'react'; + +export const WaterSanitationIcon = (props: HTMLProps) => ( + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/waves.js b/frontend/src/components/svgIcons/waves.js deleted file mode 100644 index b730b3acb2..0000000000 --- a/frontend/src/components/svgIcons/waves.js +++ /dev/null @@ -1,23 +0,0 @@ -import { PureComponent } from 'react'; - -export class WavesIcon extends PureComponent { - render() { - return ( - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/waves.tsx b/frontend/src/components/svgIcons/waves.tsx new file mode 100644 index 0000000000..4c2fa954ba --- /dev/null +++ b/frontend/src/components/svgIcons/waves.tsx @@ -0,0 +1,19 @@ +import { HTMLProps } from "react"; + +export const WavesIcon = (props: HTMLProps) => ( + + + + + + + +); diff --git a/frontend/src/components/svgIcons/worldNodes.js b/frontend/src/components/svgIcons/worldNodes.js deleted file mode 100644 index cd5261b0ea..0000000000 --- a/frontend/src/components/svgIcons/worldNodes.js +++ /dev/null @@ -1,24 +0,0 @@ -import { PureComponent } from 'react'; - -export class WorldNodesIcon extends PureComponent { - render() { - return ( - - - - - - - - - - - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/worldNodes.tsx b/frontend/src/components/svgIcons/worldNodes.tsx new file mode 100644 index 0000000000..13936c3694 --- /dev/null +++ b/frontend/src/components/svgIcons/worldNodes.tsx @@ -0,0 +1,20 @@ +import { HTMLProps } from 'react'; + +export const WorldNodesIcon = (props: HTMLProps) => ( + + + + + + + + + + + + + + + + +); diff --git a/frontend/src/components/svgIcons/youtube.js b/frontend/src/components/svgIcons/youtube.js deleted file mode 100644 index b33ddff541..0000000000 --- a/frontend/src/components/svgIcons/youtube.js +++ /dev/null @@ -1,18 +0,0 @@ -import { PureComponent } from 'react'; - -export class YoutubeIcon extends PureComponent { - render() { - return ( - - - - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/youtube.tsx b/frontend/src/components/svgIcons/youtube.tsx new file mode 100644 index 0000000000..501a3ac9f7 --- /dev/null +++ b/frontend/src/components/svgIcons/youtube.tsx @@ -0,0 +1,14 @@ +import { HTMLProps } from "react"; + +export const YoutubeIcon = (props: HTMLProps) => ( + + + + + + +); diff --git a/frontend/src/components/svgIcons/zoomPlus.js b/frontend/src/components/svgIcons/zoomPlus.js deleted file mode 100644 index 1d268b28cb..0000000000 --- a/frontend/src/components/svgIcons/zoomPlus.js +++ /dev/null @@ -1,16 +0,0 @@ -import { PureComponent } from 'react'; - -// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ -// License: CC-By 4.0 -export class ZoomPlusIcon extends PureComponent { - render() { - return ( - - - - ); - } -} diff --git a/frontend/src/components/svgIcons/zoomPlus.tsx b/frontend/src/components/svgIcons/zoomPlus.tsx new file mode 100644 index 0000000000..52aea57732 --- /dev/null +++ b/frontend/src/components/svgIcons/zoomPlus.tsx @@ -0,0 +1,12 @@ +import { HTMLProps } from 'react'; + +// Icon produced by FontAwesome project: https://github.com/FortAwesome/Font-Awesome/ +// License: CC-By 4.0 +export const ZoomPlusIcon = (props: HTMLProps) => ( + + + +); diff --git a/frontend/src/components/taskSelection/action.js b/frontend/src/components/taskSelection/action.js index abe8b0258e..61d6eb343c 100644 --- a/frontend/src/components/taskSelection/action.js +++ b/frontend/src/components/taskSelection/action.js @@ -10,7 +10,7 @@ import messages from './messages'; import { ProjectInstructions } from './instructions'; import { TasksMap } from './map'; import { HeaderLine } from '../projectDetail/header'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import Portal from '../portal'; import { SidebarIcon } from '../svgIcons'; import { openEditor, getTaskGpxUrl, formatImageryUrl, formatJosmUrl } from '../../utils/openEditor'; @@ -58,11 +58,11 @@ export function TaskMapAction({ project, tasks, activeTasks, getTasks, action, e () => activeTasks ? activeTasks - .map((task) => task.taskId) - .sort((n1, n2) => { - // in ascending order - return n1 - n2; - }) + .map((task) => task.taskId) + .sort((n1, n2) => { + // in ascending order + return n1 - n2; + }) : [], [activeTasks], ); diff --git a/frontend/src/components/taskSelection/extendSession.js b/frontend/src/components/taskSelection/extendSession.js index d6278a8f74..d0fde5c3d1 100644 --- a/frontend/src/components/taskSelection/extendSession.js +++ b/frontend/src/components/taskSelection/extendSession.js @@ -2,7 +2,7 @@ import { useState } from 'react'; import { FormattedMessage } from 'react-intl'; import Popup from 'reactjs-popup'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { Alert } from '../alert'; import { pushToLocalJSONAPI } from '../../network/genericJSONRequest'; import messages from './messages'; diff --git a/frontend/src/components/taskSelection/footer.js b/frontend/src/components/taskSelection/footer.js index 03e6113dfe..214a2d2d3a 100644 --- a/frontend/src/components/taskSelection/footer.js +++ b/frontend/src/components/taskSelection/footer.js @@ -10,7 +10,7 @@ import { openEditor, formatJosmUrl } from '../../utils/openEditor'; import { useFetchLockedTasks } from '../../hooks/UseLockedTasks'; import { pushToLocalJSONAPI, fetchLocalJSONAPI } from '../../network/genericJSONRequest'; import { Dropdown } from '../dropdown'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { Imagery } from './imagery'; import { MappingTypes } from '../mappingTypes'; import { LockedTaskModalContent } from './lockedTasks'; diff --git a/frontend/src/components/taskSelection/index.js b/frontend/src/components/taskSelection/index.tsx similarity index 97% rename from frontend/src/components/taskSelection/index.js rename to frontend/src/components/taskSelection/index.tsx index 6803d5f24b..7789489f54 100644 --- a/frontend/src/components/taskSelection/index.js +++ b/frontend/src/components/taskSelection/index.tsx @@ -31,6 +31,7 @@ import { useTasksQuery, } from '../../api/projects'; import { useTeamsQuery } from '../../api/teams'; +import { RootStore } from '../../store/index.js'; const TaskSelectionFooter = lazy(() => import('./footer')); const getRandomTaskByAction = (activities, taskAction) => { @@ -50,13 +51,16 @@ const getRandomTaskByAction = (activities, taskAction) => { } }; -export function TaskSelection({ project }: Object) { +export function TaskSelection({ project }: { + // TODO: Fix this - big type + project: any +}) { useSetProjectPageTitleTag(project); const { projectId } = project; const location = useLocation(); const dispatch = useDispatch(); - const user = useSelector((state) => state.auth.userDetails); - const userOrgs = useSelector((state) => state.auth.organisations); + const user = useSelector((state: RootStore) => state.auth.userDetails); + const userOrgs = useSelector((state: RootStore) => state.auth.organisations); const lockedTasks = useGetLockedTasks(); const [zoomedTaskId, setZoomedTaskId] = useState(null); const [activeSection, setActiveSection] = useState(null); @@ -73,17 +77,17 @@ export function TaskSelection({ project }: Object) { member: user.id, }, { - useErrorBoundary: true, + throwOnError: true, }, ); const { data: activities, refetch: getActivities } = useActivitiesQuery(projectId); const { data: contributions } = useProjectContributionsQuery(projectId, { - useErrorBoundary: true, + throwOnError: true, refetchOnWindowFocus: true, refetchInterval: activeSection === 'contributions' ? 1000 * 60 : false, }); const { data: tasksData, refetch: refetchTasks } = useTasksQuery(projectId, { - useErrorBoundary: true, + throwOnError: true, // Task status on the map were not being updated when coming from the action page, // so added this as a workaround. cacheTime: 0, @@ -239,8 +243,8 @@ export function TaskSelection({ project }: Object) { project.enforceRandomTaskSelection && taskAction !== 'validateSelectedTask' ? randomTask : selected.length && !taskAction.endsWith('AnotherTask') - ? selected - : randomTask; + ? selected + : randomTask; return (
diff --git a/frontend/src/components/taskSelection/lockedTasks.js b/frontend/src/components/taskSelection/lockedTasks.js index 065d24e485..0c65467353 100644 --- a/frontend/src/components/taskSelection/lockedTasks.js +++ b/frontend/src/components/taskSelection/lockedTasks.js @@ -5,7 +5,7 @@ import { useSelector } from 'react-redux'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { useGetLockedTasks } from '../../hooks/UseLockedTasks'; export function AnotherProjectLock({ projectId, lockedTasksLength, action }: Object) { @@ -19,9 +19,9 @@ export function AnotherProjectLock({ projectId, lockedTasksLength, action }: Obj
1 - ? 'anotherProjectLockTextPlural' - : 'anotherProjectLockTextSingular' + lockedTasksLength > 1 + ? 'anotherProjectLockTextPlural' + : 'anotherProjectLockTextSingular' ]} values={{ project: {projectId}, @@ -53,9 +53,9 @@ export function SameProjectLock({ lockedTasks, action }: Object) {
1 - ? 'currentProjectLockTextPlural' - : 'currentProjectLockTextSingular' + lockedTasks.tasks.length > 1 + ? 'currentProjectLockTextPlural' + : 'currentProjectLockTextSingular' ]} values={{ taskId: {lockedTasks.tasks} }} /> diff --git a/frontend/src/components/taskSelection/messages.js b/frontend/src/components/taskSelection/messages.ts similarity index 100% rename from frontend/src/components/taskSelection/messages.js rename to frontend/src/components/taskSelection/messages.ts diff --git a/frontend/src/components/taskSelection/permissionErrorModal.js b/frontend/src/components/taskSelection/permissionErrorModal.js index f9f34451c2..b94a193b22 100644 --- a/frontend/src/components/taskSelection/permissionErrorModal.js +++ b/frontend/src/components/taskSelection/permissionErrorModal.js @@ -4,7 +4,7 @@ import { FormattedMessage } from 'react-intl'; import messages from './messages'; import { getPermissionErrorMessage } from '../../utils/projectPermissions'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { CloseIcon } from '../svgIcons'; import { TeamBox } from '../teamsAndOrgs/teams'; diff --git a/frontend/src/components/taskSelection/tabSelector.js b/frontend/src/components/taskSelection/tabSelector.tsx similarity index 79% rename from frontend/src/components/taskSelection/tabSelector.js rename to frontend/src/components/taskSelection/tabSelector.tsx index fbc67be72f..7b3001201b 100644 --- a/frontend/src/components/taskSelection/tabSelector.js +++ b/frontend/src/components/taskSelection/tabSelector.tsx @@ -2,7 +2,10 @@ import { FormattedMessage } from 'react-intl'; import messages from './messages'; -export const TabSelector = ({ activeSection, setActiveSection }) => ( +export const TabSelector = ({ activeSection, setActiveSection }: { + activeSection: string; + setActiveSection: (section: string) => void; +}) => (
{['tasks', 'instructions', 'contributions'].map((section) => (
{ diff --git a/frontend/src/components/teamsAndOrgs/management.js b/frontend/src/components/teamsAndOrgs/management.jsx similarity index 89% rename from frontend/src/components/teamsAndOrgs/management.js rename to frontend/src/components/teamsAndOrgs/management.jsx index ec7b9561c5..d0589f6abb 100644 --- a/frontend/src/components/teamsAndOrgs/management.js +++ b/frontend/src/components/teamsAndOrgs/management.jsx @@ -6,7 +6,7 @@ import messages from './messages'; import { CustomButton } from '../button'; import { PlusIcon, WasteIcon } from '../svgIcons'; -export const ViewAllLink = ({ link }: Object) => ( +export const ViewAllLink = ({ link }) => ( @@ -23,7 +23,7 @@ export const AddButton = () => ( ); -export const DeleteButton = ({ className, onClick, showText = true }: Object) => { +export const DeleteButton = ({ className, onClick, showText = true }) => { const intl = useIntl(); return ( @@ -43,7 +43,7 @@ export const DeleteButton = ({ className, onClick, showText = true }: Object) => ); }; -export function VisibilityBox({ visibility, extraClasses }: Object) { +export function VisibilityBox({ visibility, extraClasses }) { let color = visibility === 'PUBLIC' ? 'blue-grey' : 'red'; let borderColor = visibility === 'PUBLIC' ? 'b--grey' : 'b--red'; const text = visibility ? : ''; @@ -78,9 +78,8 @@ export function Management(props) { {props.isAdmin && (
{ props.setUserOnly(false); }} @@ -88,9 +87,8 @@ export function Management(props) { { props.setUserOnly(true); }} diff --git a/frontend/src/components/teamsAndOrgs/members.js b/frontend/src/components/teamsAndOrgs/members.js index 8b84e783a4..ea210cd4af 100644 --- a/frontend/src/components/teamsAndOrgs/members.js +++ b/frontend/src/components/teamsAndOrgs/members.js @@ -7,7 +7,7 @@ import AsyncSelect from 'react-select/async'; import messages from './messages'; import { UserAvatar } from '../user/avatar'; import { EditModeControl } from './editMode'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { SwitchToggle } from '../formInputs'; import { fetchLocalJSONAPI, pushToLocalJSONAPI } from '../../network/genericJSONRequest'; import { Alert } from '../alert'; diff --git a/frontend/src/components/teamsAndOrgs/messageMembers.js b/frontend/src/components/teamsAndOrgs/messageMembers.js index c6c6698c0a..2656ff8154 100644 --- a/frontend/src/components/teamsAndOrgs/messageMembers.js +++ b/frontend/src/components/teamsAndOrgs/messageMembers.js @@ -4,7 +4,7 @@ import { FormattedMessage } from 'react-intl'; import toast from 'react-hot-toast'; import messages from './messages'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { MessageStatus } from '../comments/status'; import { pushToLocalJSONAPI } from '../../network/genericJSONRequest'; import ReactPlaceholder from 'react-placeholder'; diff --git a/frontend/src/components/teamsAndOrgs/organisations.js b/frontend/src/components/teamsAndOrgs/organisations.js index 40fca489f3..b5f93b887f 100644 --- a/frontend/src/components/teamsAndOrgs/organisations.js +++ b/frontend/src/components/teamsAndOrgs/organisations.js @@ -13,7 +13,7 @@ import { useUploadImage } from '../../hooks/UseUploadImage'; import { levels } from '../../hooks/UseOrganisationLevel'; import { Management } from './management'; import { InternalLinkIcon, ClipboardIcon } from '../svgIcons'; -import { Button } from '../button'; +import { Button } from '../button.jsx'; import { UserAvatarList } from '../user/avatar'; import { nCardPlaceholders } from './organisationsPlaceholder'; import { Alert } from '../alert'; diff --git a/frontend/src/components/user/avatar.js b/frontend/src/components/user/avatar.tsx similarity index 75% rename from frontend/src/components/user/avatar.js rename to frontend/src/components/user/avatar.tsx index 4ce38236d4..38231c74c4 100644 --- a/frontend/src/components/user/avatar.js +++ b/frontend/src/components/user/avatar.tsx @@ -5,15 +5,17 @@ import { ProfilePictureIcon, CloseIcon } from '../svgIcons'; import { getRandomArrayItem } from '../../utils/random'; import { useAvatarStyle } from '../../hooks/UseAvatarStyle'; import { useAvatarText } from '../../hooks/UseAvatarText'; +import { HtmlHTMLAttributes } from 'react'; +import { RootStore } from '../../store'; -export const CurrentUserAvatar = (props) => { - const userPicture = useSelector((state) => state.auth.userDetails.pictureUrl); +export const CurrentUserAvatar = (props: HtmlHTMLAttributes) => { + const userPicture = useSelector((state: RootStore) => state.auth.userDetails?.pictureUrl); if (userPicture) { return (
); } @@ -21,7 +23,6 @@ export const CurrentUserAvatar = (props) => { }; export const UserAvatar = ({ - name, username, number, picture, @@ -30,7 +31,16 @@ export const UserAvatar = ({ removeFn, editMode, disableLink = false, -}: Object) => { +}: { + username: string; + number?: string; + picture?: string; + size?: string; + colorClasses?: string; + removeFn?: Function; + editMode?: boolean; + disableLink?: boolean; +}) => { const avatarText = useAvatarText(name, username, number); if ((removeFn && editMode) || disableLink) { @@ -62,7 +72,17 @@ export const UserAvatar = ({ } }; -const Avatar = ({ username, size, colorClasses, removeFn, picture, text, editMode }) => { +const Avatar = ({ username, size, colorClasses, removeFn, picture, text, editMode }: { + username: string; + number?: string; + picture?: string; + text: string; + size?: "small" | "medium" | "large"; + colorClasses?: string; + removeFn?: Function; + editMode?: boolean; + disableLink?: boolean; +}) => { const { sizeClasses, textPadding, closeIconStyle, sizeStyle } = useAvatarStyle( size, editMode, @@ -101,7 +121,14 @@ export const UserAvatarList = ({ bgColor, size, totalCount, -}: Object) => { +}: { + users: any[]; + maxLength?: number; + textColor?: string; + bgColor?: string; + size?: string; + totalCount?: number; +}) => { const getColor = () => bgColor ? bgColor : getRandomArrayItem(['bg-orange', 'bg-red', 'bg-blue-dark', 'bg-blue-grey']); let marginLeft = '-1.25rem'; @@ -127,11 +154,12 @@ export const UserAvatarList = ({ {maxLength && (totalCount || users.length) - maxLength > 0 && (
999 - ? 999 - : (totalCount || users.length) - maxLength - }`} + // TODO: Fix this, it shouldn't really just be an empty string + username={""} + number={`+${(totalCount || users.length) - maxLength > 999 + ? 999 + : (totalCount || users.length) - maxLength + }`} size={size} colorClasses={`blue-dark bg-grey-light`} disableLink={true} diff --git a/frontend/src/components/user/forms/personalInformation.js b/frontend/src/components/user/forms/personalInformation.tsx similarity index 95% rename from frontend/src/components/user/forms/personalInformation.js rename to frontend/src/components/user/forms/personalInformation.tsx index bd6a20a202..69b084bf50 100644 --- a/frontend/src/components/user/forms/personalInformation.js +++ b/frontend/src/components/user/forms/personalInformation.tsx @@ -11,6 +11,7 @@ import { UserCountrySelect, RadioField } from '../../formInputs'; import { pushUserDetails } from '../../../store/actions/auth'; import { fetchLocalJSONAPI } from '../../../network/genericJSONRequest'; import { ORG_CODE } from '../../../config'; +import { RootStore } from '../../../store'; export const PROFILE_RELEVANT_FIELDS = [ 'name', @@ -66,7 +67,7 @@ const genderOptions = [ }, ]; -const mapStateToProps = (state) => ({ +const mapStateToProps = (state: RootStore) => ({ userDetails: state.auth.userDetails, token: state.auth.token, }); @@ -95,14 +96,14 @@ function _PersonalInformationForm({ userDetails, token, pushUserDetails }) { const composeValidators = (...validators) => - (value) => - validators.reduce((error, validator) => error || validator(value), undefined); + (value) => + validators.reduce((error, validator) => error || validator(value), undefined); const isUrl = (value) => value && - value.match( - /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/gi, - ) ? ( + value.match( + /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/gi, + ) ? ( ) : undefined; diff --git a/frontend/src/config/index.js b/frontend/src/config/index.ts similarity index 55% rename from frontend/src/config/index.js rename to frontend/src/config/index.ts index b5b11362c9..cdbf71fd2c 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.ts @@ -1,66 +1,66 @@ // API ENDPOINTS -export const API_VERSION = process.env.REACT_APP_API_VERSION || 'v2'; -export const API_URL = process.env.REACT_APP_API_URL - ? new URL('/api/' + API_VERSION + '/', process.env.REACT_APP_API_URL) +export const API_VERSION = import.meta.env.REACT_APP_API_VERSION || 'v2'; +export const API_URL = import.meta.env.REACT_APP_API_URL + ? new URL('/api/' + API_VERSION + '/', import.meta.env.REACT_APP_API_URL) : 'http://127.0.0.1:5000/api/' + API_VERSION + '/'; export const OHSOME_STATS_BASE_URL = - process.env.REACT_APP_OHSOME_STATS_BASE_URL || 'https://stats.now.ohsome.org/api'; + import.meta.env.REACT_APP_OHSOME_STATS_BASE_URL || 'https://stats.now.ohsome.org/api'; // APPLICATION SETTINGS -export const DEFAULT_LOCALE = process.env.REACT_APP_DEFAULT_LOCALE || 'en'; -export const ENVIRONMENT = process.env.REACT_APP_ENVIRONMENT || ''; +export const DEFAULT_LOCALE = import.meta.env.REACT_APP_DEFAULT_LOCALE || 'en'; +export const ENVIRONMENT = import.meta.env.REACT_APP_ENVIRONMENT || ''; export const PROJECTCARD_CONTRIBUTION_SHOWN_THRESHOLD = - process.env.REACT_APP_PROJECTCARD_CONTRIBUTION_SHOWN_THRESHOLD || 5; + import.meta.env.REACT_APP_PROJECTCARD_CONTRIBUTION_SHOWN_THRESHOLD || 5; export const INTERMEDIATE_LEVEL_COUNT = - Number(process.env.REACT_APP_TM_MAPPER_LEVEL_INTERMEDIATE) || 250; -export const ADVANCED_LEVEL_COUNT = Number(process.env.REACT_APP_TM_MAPPER_LEVEL_ADVANCED) || 500; -export const MAPBOX_TOKEN = process.env.REACT_APP_MAPBOX_TOKEN || ''; -export const ENABLE_SERVICEWORKER = process.env.REACT_APP_ENABLE_SERVICEWORKER || 0; -export const MAX_AOI_AREA = Number(process.env.REACT_APP_MAX_AOI_AREA) || 5000; -export const MAX_FILESIZE = parseInt(process.env.REACT_APP_MAX_FILESIZE) || 1000000; // bytes + Number(import.meta.env.REACT_APP_TM_MAPPER_LEVEL_INTERMEDIATE) || 250; +export const ADVANCED_LEVEL_COUNT = Number(import.meta.env.REACT_APP_TM_MAPPER_LEVEL_ADVANCED) || 500; +export const MAPBOX_TOKEN = import.meta.env.REACT_APP_MAPBOX_TOKEN || ''; +export const ENABLE_SERVICEWORKER = import.meta.env.REACT_APP_ENABLE_SERVICEWORKER || 0; +export const MAX_AOI_AREA = Number(import.meta.env.REACT_APP_MAX_AOI_AREA) || 5000; +export const MAX_FILESIZE = parseInt(import.meta.env.REACT_APP_MAX_FILESIZE) || 1000000; // bytes // ORGANISATIONAL INFORMATION -export const ORG_NAME = process.env.REACT_APP_ORG_NAME || 'Humanitarian OpenStreetMap Team'; -export const ORG_CODE = process.env.REACT_APP_ORG_CODE || 'HOT'; -export const ORG_URL = process.env.REACT_APP_ORG_URL || ''; -export const ORG_LOGO = process.env.REACT_APP_ORG_LOGO || ''; -export const HOMEPAGE_IMG_HIGH = process.env.REACT_APP_HOMEPAGE_IMG_HIGH || ''; -export const HOMEPAGE_IMG_LOW = process.env.REACT_APP_HOMEPAGE_IMG_LOW || ''; -export const OSM_CLIENT_ID = process.env.REACT_APP_OSM_CLIENT_ID || ''; -export const OSM_CLIENT_SECRET = process.env.REACT_APP_OSM_CLIENT_SECRET || ''; -export const OSM_REDIRECT_URI = process.env.REACT_APP_OSM_REDIRECT_URI || ''; -export const ORG_PRIVACY_POLICY_URL = process.env.REACT_APP_ORG_PRIVACY_POLICY_URL || ''; +export const ORG_NAME = import.meta.env.REACT_APP_ORG_NAME || 'Humanitarian OpenStreetMap Team'; +export const ORG_CODE = import.meta.env.REACT_APP_ORG_CODE || 'HOT'; +export const ORG_URL = import.meta.env.REACT_APP_ORG_URL || ''; +export const ORG_LOGO = import.meta.env.REACT_APP_ORG_LOGO || ''; +export const HOMEPAGE_IMG_HIGH = import.meta.env.REACT_APP_HOMEPAGE_IMG_HIGH || ''; +export const HOMEPAGE_IMG_LOW = import.meta.env.REACT_APP_HOMEPAGE_IMG_LOW || ''; +export const OSM_CLIENT_ID = import.meta.env.REACT_APP_OSM_CLIENT_ID || ''; +export const OSM_CLIENT_SECRET = import.meta.env.REACT_APP_OSM_CLIENT_SECRET || ''; +export const OSM_REDIRECT_URI = import.meta.env.REACT_APP_OSM_REDIRECT_URI || ''; +export const ORG_PRIVACY_POLICY_URL = import.meta.env.REACT_APP_ORG_PRIVACY_POLICY_URL || ''; export const OSM_REGISTER_URL = - process.env.REACT_APP_OSM_REGISTER_URL || 'https://www.openstreetmap.org/user/new'; -export const ORG_TWITTER = process.env.REACT_APP_ORG_TWITTER || 'https://twitter.com/hotosm'; -export const ORG_FB = process.env.REACT_APP_ORG_FB || 'https://www.facebook.com/hotosm'; + import.meta.env.REACT_APP_OSM_REGISTER_URL || 'https://www.openstreetmap.org/user/new'; +export const ORG_TWITTER = import.meta.env.REACT_APP_ORG_TWITTER || 'https://twitter.com/hotosm'; +export const ORG_FB = import.meta.env.REACT_APP_ORG_FB || 'https://www.facebook.com/hotosm'; export const ORG_INSTAGRAM = - process.env.REACT_APP_ORG_INSTAGRAM || 'https://www.instagram.com/open.mapping.hubs/'; + import.meta.env.REACT_APP_ORG_INSTAGRAM || 'https://www.instagram.com/open.mapping.hubs/'; export const ORG_YOUTUBE = - process.env.REACT_APP_ORG_YOUTUBE || 'https://www.youtube.com/user/hotosm'; -export const ORG_GITHUB = process.env.REACT_APP_ORG_GITHUB || 'https://github.com/hotosm'; -export const MATOMO_ID = process.env.REACT_APP_MATOMO_ID || ''; -export const SERVICE_DESK = process.env.REACT_APP_SERVICE_DESK || ''; -export const IMAGE_UPLOAD_SERVICE = process.env.REACT_APP_IMAGE_UPLOAD_API_URL || ''; + import.meta.env.REACT_APP_ORG_YOUTUBE || 'https://www.youtube.com/user/hotosm'; +export const ORG_GITHUB = import.meta.env.REACT_APP_ORG_GITHUB || 'https://github.com/hotosm'; +export const MATOMO_ID = import.meta.env.REACT_APP_MATOMO_ID || ''; +export const SERVICE_DESK = import.meta.env.REACT_APP_SERVICE_DESK || ''; +export const IMAGE_UPLOAD_SERVICE = import.meta.env.REACT_APP_IMAGE_UPLOAD_API_URL || ''; export const TM_DEFAULT_CHANGESET_COMMENT = - process.env.REACT_APP_TM_DEFAULT_CHANGESET_COMMENT || '#hotosm-project'; -export const HOMEPAGE_VIDEO_URL = process.env.REACT_APP_HOMEPAGE_VIDEO_URL || ''; + import.meta.env.REACT_APP_TM_DEFAULT_CHANGESET_COMMENT || '#hotosm-project'; +export const HOMEPAGE_VIDEO_URL = import.meta.env.REACT_APP_HOMEPAGE_VIDEO_URL || ''; // Sentry.io DSN -export const SENTRY_FRONTEND_DSN = process.env.REACT_APP_SENTRY_FRONTEND_DSN; +export const SENTRY_FRONTEND_DSN = import.meta.env.REACT_APP_SENTRY_FRONTEND_DSN; // OSM API and Editor URLs export const OSM_SERVER_URL = - process.env.REACT_APP_OSM_SERVER_URL || 'https://www.openstreetmap.org'; + import.meta.env.REACT_APP_OSM_SERVER_URL || 'https://www.openstreetmap.org'; export const OSM_SERVER_API_URL = - process.env.REACT_APP_OSM_SERVER_API_URL || 'https://api.openstreetmap.org'; + import.meta.env.REACT_APP_OSM_SERVER_API_URL || 'https://api.openstreetmap.org'; export const ID_EDITOR_URL = - process.env.REACT_APP_ID_EDITOR_URL || 'https://www.openstreetmap.org/edit?editor=id&'; + import.meta.env.REACT_APP_ID_EDITOR_URL || 'https://www.openstreetmap.org/edit?editor=id&'; export const POTLATCH2_EDITOR_URL = - process.env.REACT_APP_POTLATCH2_EDITOR_URL || + import.meta.env.REACT_APP_POTLATCH2_EDITOR_URL || 'https://www.openstreetmap.org/edit?editor=potlatch2'; export const RAPID_EDITOR_URL = - process.env.REACT_APP_RAPID_EDITOR_URL || 'https://mapwith.ai/rapid'; -export const EXPORT_TOOL_S3_URL = process.env.REACT_APP_EXPORT_TOOL_S3_URL || ''; -export const ENABLE_EXPORT_TOOL = process.env.REACT_APP_ENABLE_EXPORT_TOOL || ''; + import.meta.env.REACT_APP_RAPID_EDITOR_URL || 'https://mapwith.ai/rapid'; +export const EXPORT_TOOL_S3_URL = import.meta.env.REACT_APP_EXPORT_TOOL_S3_URL || ''; +export const ENABLE_EXPORT_TOOL = import.meta.env.REACT_APP_ENABLE_EXPORT_TOOL || ''; export const TASK_COLOURS = { READY: '#fff', @@ -173,7 +173,7 @@ export const MAP_STYLE = MAPBOX_TOKEN export const MAPBOX_RTL_PLUGIN_URL = 'https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-rtl-text/v0.2.0/mapbox-gl-rtl-text.js'; -export const UNDERPASS_URL = process.env.REACT_APP_UNDERPASS_URL || 'https://underpass.hotosm.org'; +export const UNDERPASS_URL = import.meta.env.REACT_APP_UNDERPASS_URL || 'https://underpass.hotosm.org'; export const DROPZONE_SETTINGS = { accept: { diff --git a/frontend/src/globalFix.ts b/frontend/src/globalFix.ts new file mode 100644 index 0000000000..d95f66e90d --- /dev/null +++ b/frontend/src/globalFix.ts @@ -0,0 +1,2 @@ +// https://stackoverflow.com/questions/72114775/vite-global-is-not-defined +window.global ||= window; diff --git a/frontend/src/hooks/UseAsync.js b/frontend/src/hooks/UseAsync.ts similarity index 90% rename from frontend/src/hooks/UseAsync.js rename to frontend/src/hooks/UseAsync.ts index 1f41c7a16e..25010a6620 100644 --- a/frontend/src/hooks/UseAsync.js +++ b/frontend/src/hooks/UseAsync.ts @@ -2,7 +2,7 @@ import { useState, useCallback, useEffect } from 'react'; // source: https://usehooks.com/useAsync/ (with modifications) -export const useAsync = (asyncFunction, immediate = false) => { +export const useAsync = (asyncFunction: () => Promise, immediate = false) => { const [status, setStatus] = useState('idle'); const [value, setValue] = useState(null); const [error, setError] = useState(null); @@ -12,7 +12,7 @@ export const useAsync = (asyncFunction, immediate = false) => { // useCallback ensures the below useEffect is not called // on every render, but only if asyncFunction changes. const execute = useCallback( - (param = null) => { + async (param = null) => { setStatus('pending'); setValue(null); setError(null); diff --git a/frontend/src/hooks/UseAvatarStyle.js b/frontend/src/hooks/UseAvatarStyle.tsx similarity index 81% rename from frontend/src/hooks/UseAvatarStyle.js rename to frontend/src/hooks/UseAvatarStyle.tsx index e309f41738..7c28397253 100644 --- a/frontend/src/hooks/UseAvatarStyle.js +++ b/frontend/src/hooks/UseAvatarStyle.tsx @@ -1,10 +1,10 @@ import { useState, useEffect } from 'react'; -export const useAvatarStyle = (size, editMode, picture) => { +export const useAvatarStyle = (size?: "small" | "medium" | "large", editMode?: boolean, picture?: string) => { const [sizeClasses, setSizeClasses] = useState('h2 w2 f5'); const [textPadding, setTextPadding] = useState({}); const [sizeStyle, setSizeStyle] = useState({}); - const [closeIconStyle, setCloseIconStyle] = useState({ left: '0.4rem' }); + const [closeIconStyle, setCloseIconStyle] = useState>({ left: '0.4rem' }); useEffect(() => { if (size === 'large') setSizeClasses('h3 w3 f2'); @@ -26,7 +26,7 @@ export const useAvatarStyle = (size, editMode, picture) => { }, [size]); useEffect(() => { if (size === 'small') { - const smallStyle = { height: '1.5rem', width: '1.5rem' }; + const smallStyle: Partial = { height: '1.5rem', width: '1.5rem' }; if (picture) smallStyle.backgroundImage = `url("${picture}")`; setSizeStyle(smallStyle); } else { diff --git a/frontend/src/hooks/UseFetch.js b/frontend/src/hooks/UseFetch.ts similarity index 63% rename from frontend/src/hooks/UseFetch.js rename to frontend/src/hooks/UseFetch.ts index 97fc5484ef..3b43ee0367 100644 --- a/frontend/src/hooks/UseFetch.js +++ b/frontend/src/hooks/UseFetch.ts @@ -3,13 +3,14 @@ import { useSelector } from 'react-redux'; import { fetchLocalJSONAPI, fetchLocalJSONAPIWithAbort } from '../network/genericJSONRequest'; import { useInterval } from './UseInterval'; +import { RootStore } from '../store'; -export const useFetch = (url, trigger = true) => { - const token = useSelector((state) => state.auth.token); - const locale = useSelector((state) => state.preferences['locale']); - const [error, setError] = useState(null); +export const useFetch = (url: string, trigger: boolean = true) => { + const token = useSelector((state: RootStore) => state.auth.token); + const locale = useSelector((state: RootStore) => state.preferences['locale']); + const [error, setError] = useState(null); const [loading, setLoading] = useState(true); - const [data, setData] = useState({}); + const [data, setData] = useState({}); useEffect(() => { (async () => { @@ -26,8 +27,10 @@ export const useFetch = (url, trigger = true) => { setData(response); setLoading(false); } catch (e) { - setError(e); - setLoading(false); + if (e instanceof Error) { + setError(e.message); + setLoading(false); + } } } })(); @@ -35,12 +38,12 @@ export const useFetch = (url, trigger = true) => { return [error, loading, data]; }; -export const useFetchWithAbort = (url, trigger = true) => { - const token = useSelector((state) => state.auth.token); - const locale = useSelector((state) => state.preferences['locale']); - const [error, setError] = useState(null); +export const useFetchWithAbort = (url: string, trigger: boolean = true) => { + const token = useSelector((state: RootStore) => state.auth.token); + const locale = useSelector((state: RootStore) => state.preferences['locale']); + const [error, setError] = useState(null); const [loading, setLoading] = useState(true); - const [data, setData] = useState({}); + const [data, setData] = useState(null); const [refetchIndex, setRefetchIndex] = useState(0); // Component using refetch would infinitely make requests @@ -68,8 +71,10 @@ export const useFetchWithAbort = (url, trigger = true) => { setLoading(false); } catch (e) { if (signal.aborted) return; - setError(e); - setLoading(false); + if (e instanceof Error) { + setError(e.message); + setLoading(false); + } } } })(); @@ -79,11 +84,11 @@ export const useFetchWithAbort = (url, trigger = true) => { return [error, loading, data, refetch]; }; -export function useFetchIntervaled(url, delay, trigger = true) { - const token = useSelector((state) => state.auth.token); - const locale = useSelector((state) => state.preferences['locale']); +export function useFetchIntervaled(url: string, delay: number, trigger = true) { + const token = useSelector((state: RootStore) => state.auth.token); + const locale = useSelector((state: RootStore) => state.preferences['locale']); const [data, setData] = useState(); - const [error, setError] = useState(null); + const [error, setError] = useState(null); useInterval(() => { (async () => { @@ -93,7 +98,12 @@ export function useFetchIntervaled(url, delay, trigger = true) { const response = await fetchLocalJSONAPI(url, token, 'GET', locale.replace('-', '_')); setData(response); } catch (e) { - setError(e); + if (e instanceof Error) { + if (e.name === 'AbortError') { + return; + } + setError(e.message); + } } } })(); diff --git a/frontend/src/hooks/UseFirstTaskActionDate.js b/frontend/src/hooks/UseFirstTaskActionDate.ts similarity index 75% rename from frontend/src/hooks/UseFirstTaskActionDate.js rename to frontend/src/hooks/UseFirstTaskActionDate.ts index d57489f9a0..c41fa3eec6 100644 --- a/frontend/src/hooks/UseFirstTaskActionDate.js +++ b/frontend/src/hooks/UseFirstTaskActionDate.ts @@ -2,8 +2,10 @@ import { useEffect, useState } from 'react'; import { compareHistoryLastUpdate } from '../utils/sorting'; -const useFirstTaskActionDate = (history) => { - const [firstDate, setFirstDate] = useState(null); +const useFirstTaskActionDate = (history: { + taskHistory: { actionDate: string }[]; +}) => { + const [firstDate, setFirstDate] = useState(null); useEffect(() => { if (history && history.taskHistory && history.taskHistory.length) { const fistTaskAction = diff --git a/frontend/src/hooks/UseGetContributors.js b/frontend/src/hooks/UseGetContributors.ts similarity index 69% rename from frontend/src/hooks/UseGetContributors.js rename to frontend/src/hooks/UseGetContributors.ts index 961e6e209d..f40d967a44 100644 --- a/frontend/src/hooks/UseGetContributors.js +++ b/frontend/src/hooks/UseGetContributors.ts @@ -1,9 +1,11 @@ import { useCallback } from 'react'; -const useGetContributors = (history) => { +const useGetContributors = (history: { + taskHistory: { usernames: string[]; actionBy: string }[]; +}) => { const getContributors = useCallback(() => { if (history && history.taskHistory && history.taskHistory.length) { - return history.taskHistory.reduce((usernames, item) => { + return history.taskHistory.reduce((usernames, item) => { if (!usernames.includes(item.actionBy)) { usernames.push(item.actionBy); } diff --git a/frontend/src/hooks/UseInterval.js b/frontend/src/hooks/UseInterval.ts similarity index 69% rename from frontend/src/hooks/UseInterval.js rename to frontend/src/hooks/UseInterval.ts index 0a2d2163f9..40d569aba8 100644 --- a/frontend/src/hooks/UseInterval.js +++ b/frontend/src/hooks/UseInterval.ts @@ -1,7 +1,7 @@ import { useEffect, useRef } from 'react'; -export function useInterval(callback, delay) { - const savedCallback = useRef(); +export function useInterval(callback: () => void, delay: number) { + const savedCallback = useRef void)>(); // Remember the latest callback. useEffect(() => { @@ -11,7 +11,7 @@ export function useInterval(callback, delay) { // Set up the interval. useEffect(() => { function tick() { - savedCallback.current(); + savedCallback.current?.(); } if (delay !== null) { let id = setInterval(tick, delay); diff --git a/frontend/src/hooks/UseThrottle.js b/frontend/src/hooks/UseThrottle.ts similarity index 89% rename from frontend/src/hooks/UseThrottle.js rename to frontend/src/hooks/UseThrottle.ts index 54518c36cc..c73282a0ec 100644 --- a/frontend/src/hooks/UseThrottle.js +++ b/frontend/src/hooks/UseThrottle.ts @@ -1,7 +1,7 @@ /* https://github.com/bhaskarGyan/use-throttle#readme */ import { useState, useEffect, useRef, useCallback } from 'react'; -export const useThrottle = (value, limit) => { +export const useThrottle = (value: string, limit: number) => { const [throttledValue, setThrottledValue] = useState(value); const lastRan = useRef(Date.now()); @@ -22,19 +22,24 @@ export const useThrottle = (value, limit) => { }; /* https://github.com/xnimorz/use-debounce based on 3.3.0 compiled from TypeScript */ -export function useDebouncedCallback(callback, delay, options = {}) { +export function useDebouncedCallback(callback: (arg: T) => void, delay: number, options: { + maxWait?: number; + leading?: boolean; + trailing?: boolean; +} = {}) { const maxWait = options.maxWait; - const maxWaitHandler = useRef(null); + const maxWaitHandler = useRef(null); const maxWaitArgs = useRef([]); const leading = options.leading; const trailing = options.trailing === undefined ? true : options.trailing; const leadingCall = useRef(false); - const functionTimeoutHandler = useRef(null); + const functionTimeoutHandler = useRef(null); const isComponentUnmounted = useRef(false); const debouncedFunction = useRef(callback); debouncedFunction.current = callback; const cancelDebouncedCallback = useCallback(() => { - clearTimeout(functionTimeoutHandler.current); + if (!functionTimeoutHandler.current || !maxWaitHandler.current) return; + clearTimeout(functionTimeoutHandler?.current); clearTimeout(maxWaitHandler.current); maxWaitHandler.current = null; maxWaitArgs.current = []; @@ -49,9 +54,11 @@ export function useDebouncedCallback(callback, delay, options = {}) { [], ); const debouncedCallback = useCallback( - (...args) => { + (...args: any) => { maxWaitArgs.current = args; - clearTimeout(functionTimeoutHandler.current); + if (functionTimeoutHandler.current) { + clearTimeout(functionTimeoutHandler.current); + } if (leadingCall.current) { leadingCall.current = false; } diff --git a/frontend/src/hooks/UseTimeDiff.js b/frontend/src/hooks/UseTimeDiff.js deleted file mode 100644 index ebde6f685b..0000000000 --- a/frontend/src/hooks/UseTimeDiff.js +++ /dev/null @@ -1,18 +0,0 @@ -import { useState, useEffect } from 'react'; - -export function useTimeDiff(tasksByDay) { - const [unit, setUnit] = useState('day'); - const day = 86400000; - useEffect(() => { - if (tasksByDay && tasksByDay.length >= 2) { - const timeDiff = - (new Date(tasksByDay[tasksByDay.length - 1].date) - new Date(tasksByDay[0].date)) / day; - if (timeDiff > 16 * 7) { - setUnit('month'); - } else if (timeDiff > 16) { - setUnit('week'); - } - } - }, [tasksByDay]); - return unit; -} diff --git a/frontend/src/hooks/UseTimeDiff.ts b/frontend/src/hooks/UseTimeDiff.ts new file mode 100644 index 0000000000..969ef807dc --- /dev/null +++ b/frontend/src/hooks/UseTimeDiff.ts @@ -0,0 +1,19 @@ +import type { TimeUnit } from 'chart.js'; +import { differenceInDays } from 'date-fns'; +import { useState, useEffect } from 'react'; + +export function useTimeDiff(tasksByDay: { date: string }[]) { + const [unit, setUnit] = useState('day'); + useEffect(() => { + if (tasksByDay && tasksByDay.length >= 2) { + const timeDiff = differenceInDays(tasksByDay[tasksByDay.length - 1].date, new Date(tasksByDay[0].date)) + // If the time difference is greater than 16 weeks, set the unit to month + if (timeDiff > 16 * 7) { + setUnit('month'); + } else if (timeDiff > 16) { // If the time difference is greater than 16 days, set the unit to week + setUnit('week'); + } + } + }, [tasksByDay]); + return unit; +} diff --git a/frontend/src/hooks/UseUploadImage.js b/frontend/src/hooks/UseUploadImage.ts similarity index 83% rename from frontend/src/hooks/UseUploadImage.js rename to frontend/src/hooks/UseUploadImage.ts index 55ba8fc58e..82720711df 100644 --- a/frontend/src/hooks/UseUploadImage.js +++ b/frontend/src/hooks/UseUploadImage.ts @@ -3,12 +3,13 @@ import { useSelector } from 'react-redux'; import { pushToLocalJSONAPI } from '../network/genericJSONRequest'; import { slugifyFileName } from '../utils/slugifyFileName'; +import { RootStore } from '../store'; export const useUploadImage = () => { const [uploading, setUploading] = useState(false); const [uploadError, setUploadError] = useState(null); - const uploadImg = useCallback((file, updateFn, token) => { + const uploadImg = useCallback((file: File, updateFn: any, token: string) => { if (file && updateFn && token) { const promise = new Promise((resolve, reject) => { const reader = new FileReader(); @@ -25,6 +26,7 @@ export const useUploadImage = () => { (result) => { const payload = JSON.stringify({ mime: file.type, + // @ts-expect-error TS Migrations data: result.split('base64,')[1], filename: slugifyFileName(file.name, file.type), }); @@ -49,12 +51,14 @@ export const useUploadImage = () => { return [uploadError, uploading, uploadImg]; }; -export const useOnDrop = (appendImgToComment) => { - const token = useSelector((state) => state.auth.token); +export const useOnDrop = (appendImgToComment: string) => { + const token = useSelector((state: RootStore) => state.auth.token); const [uploadError, uploading, uploadImg] = useUploadImage(); const onDrop = useCallback( + // @ts-expect-error TS Migrations (acceptedFiles) => { + // @ts-expect-error TS Migrations acceptedFiles.forEach(async (file) => await uploadImg(file, appendImgToComment, token)); }, [token, uploadImg, appendImgToComment], diff --git a/frontend/src/index.js b/frontend/src/index.tsx similarity index 94% rename from frontend/src/index.js rename to frontend/src/index.tsx index 6f8255a64c..bd4f683436 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.tsx @@ -1,3 +1,4 @@ +import "./globalFix" import { createRoot } from 'react-dom/client'; import { PersistGate } from 'redux-persist/integration/react'; import { Provider } from 'react-redux'; @@ -5,9 +6,9 @@ import { load } from 'webfontloader'; import { init, BrowserTracing, Replay } from '@sentry/react'; import 'react-tooltip/dist/react-tooltip.css'; // Needed by for { Tooltip } from 'react-tooltip' to work properly -import App from './App'; +import App from './App.jsx'; import { store, persistor } from './store'; -import { ConnectedIntl } from './utils/internationalization'; +import { ConnectedIntl } from './utils/internationalization.jsx'; import { register, unregister, onServiceWorkerUpdate } from './serviceWorkerRegistration'; import { ENABLE_SERVICEWORKER, SENTRY_FRONTEND_DSN, ENVIRONMENT } from './config'; diff --git a/frontend/src/network/genericJSONRequest.js b/frontend/src/network/genericJSONRequest.ts similarity index 80% rename from frontend/src/network/genericJSONRequest.js rename to frontend/src/network/genericJSONRequest.ts index 6bb9af7b08..34e0e50b7e 100644 --- a/frontend/src/network/genericJSONRequest.js +++ b/frontend/src/network/genericJSONRequest.ts @@ -7,11 +7,12 @@ import { API_URL } from '../config'; * @param {RequestInit} [init={}}] Any specific init options you want to pass the fetch (such as an {@link AbortSignal}) * @returns {Promise<*>} A promise that returns a JSON or an error */ -export function fetchExternalJSONAPI(url, init = {}): Promise<*> { - if (!init.headers) { - init.headers = { 'Content-Type': 'application/json' }; +export function fetchExternalJSONAPI(url: string, init?: { + headers: any +}) { + if (init?.headers) { + init.headers['Content-Type'] = 'application/json'; } - init.headers['Content-Type'] = 'application/json'; return fetch(url, { method: 'GET', @@ -23,12 +24,13 @@ export function fetchExternalJSONAPI(url, init = {}): Promise<*> { }); } -export function fetchLocalJSONAPI(endpoint, token, method = 'GET', language = 'en'): Promise<*> { +export function fetchLocalJSONAPI(endpoint: string, token: string, method = 'GET', language = 'en') { const url = new URL(endpoint, API_URL); let headers = { 'Content-Type': 'application/json', 'Accept-Language': language.replace('-', '_'), - }; + } as Record; + if (token) { headers['Authorization'] = `Token ${token}`; } @@ -43,9 +45,9 @@ export function fetchLocalJSONAPI(endpoint, token, method = 'GET', language = 'e } export function fetchLocalJSONAPIWithAbort( - endpoint, - token, - signal, + endpoint: string, + token: string, + signal: AbortSignal, method = 'GET', language = 'en', ) { @@ -53,7 +55,7 @@ export function fetchLocalJSONAPIWithAbort( let headers = { 'Content-Type': 'application/json', 'Accept-Language': language.replace('-', '_'), - }; + } as Record if (token) { headers['Authorization'] = `Token ${token}`; } @@ -69,12 +71,12 @@ export function fetchLocalJSONAPIWithAbort( } export function pushToLocalJSONAPI( - endpoint, - payload, - token, + endpoint: string, + payload: string, + token: string, method = 'POST', language = 'en', -): Promise<*> { +) { const url = new URL(endpoint, API_URL); return fetch(url, { method: method, diff --git a/frontend/src/network/tests/mockData/auth.js b/frontend/src/network/tests/mockData/auth.ts similarity index 100% rename from frontend/src/network/tests/mockData/auth.js rename to frontend/src/network/tests/mockData/auth.ts diff --git a/frontend/src/network/tests/mockData/contributions.js b/frontend/src/network/tests/mockData/contributions.ts similarity index 100% rename from frontend/src/network/tests/mockData/contributions.js rename to frontend/src/network/tests/mockData/contributions.ts diff --git a/frontend/src/network/tests/mockData/featuredProjects.js b/frontend/src/network/tests/mockData/featuredProjects.ts similarity index 100% rename from frontend/src/network/tests/mockData/featuredProjects.js rename to frontend/src/network/tests/mockData/featuredProjects.ts diff --git a/frontend/src/network/tests/mockData/homepageStats.js b/frontend/src/network/tests/mockData/homepageStats.ts similarity index 100% rename from frontend/src/network/tests/mockData/homepageStats.js rename to frontend/src/network/tests/mockData/homepageStats.ts diff --git a/frontend/src/network/tests/mockData/management.js b/frontend/src/network/tests/mockData/management.ts similarity index 98% rename from frontend/src/network/tests/mockData/management.js rename to frontend/src/network/tests/mockData/management.ts index 63d5cbfa61..3aad78fd68 100644 --- a/frontend/src/network/tests/mockData/management.js +++ b/frontend/src/network/tests/mockData/management.ts @@ -99,7 +99,7 @@ export const interestCreationSuccess = (name) => ({ name, }); -export const interestUpdationSuccess = (name) => ({ +export const interestUpdationSuccess = (name: string) => ({ id: 123, name, }); diff --git a/frontend/src/network/tests/mockData/miscellaneous.js b/frontend/src/network/tests/mockData/miscellaneous.ts similarity index 100% rename from frontend/src/network/tests/mockData/miscellaneous.js rename to frontend/src/network/tests/mockData/miscellaneous.ts diff --git a/frontend/src/network/tests/mockData/notifications.js b/frontend/src/network/tests/mockData/notifications.ts similarity index 91% rename from frontend/src/network/tests/mockData/notifications.js rename to frontend/src/network/tests/mockData/notifications.ts index fc5ec7dd4f..b7e3a1b176 100644 --- a/frontend/src/network/tests/mockData/notifications.js +++ b/frontend/src/network/tests/mockData/notifications.ts @@ -1,4 +1,4 @@ -export function generateSampleNotifications(numSamples) { +export function generateSampleNotifications(numSamples: number) { const sampleData = []; for (let i = 0; i < numSamples; i++) { @@ -11,8 +11,8 @@ export function generateSampleNotifications(numSamples) { i % 3 === 0 ? 'REQUEST_TEAM_NOTIFICATION' : i % 3 === 1 - ? 'INVITATION_NOTIFICATION' - : 'TEAM_BROADCAST'; + ? 'INVITATION_NOTIFICATION' + : 'TEAM_BROADCAST'; const sentDate = new Date().toISOString(); const read = i % 3 !== 0; diff --git a/frontend/src/network/tests/mockData/projects.js b/frontend/src/network/tests/mockData/projects.ts similarity index 97% rename from frontend/src/network/tests/mockData/projects.js rename to frontend/src/network/tests/mockData/projects.ts index 258bf929e5..48ce6b0a8e 100644 --- a/frontend/src/network/tests/mockData/projects.js +++ b/frontend/src/network/tests/mockData/projects.ts @@ -13,9 +13,9 @@ const status = { [PROJECT_ID_ALL_MAPPED]: { mappedPercent: 100, }, -}; +} as const; -export const getProjectSummary = (id) => ({ +export const getProjectSummary = (id: number) => ({ projectId: id, defaultLocale: 'en', author: 'test_user', @@ -40,8 +40,8 @@ export const getProjectSummary = (id) => ({ osmchaFilterId: '9322aa63-cccc-4d0d-9f93-403678e52345', mappingTypes: ['BUILDINGS'], changesetComment: `${TM_DEFAULT_CHANGESET_COMMENT}-${id} #brumado-buildings`, - percentMapped: status[id]?.mappedPercent || 16, - percentValidated: status[id]?.validatedPercent || 6, + percentMapped: (id === PROJECT_ID_ALL_VALIDATED || id === PROJECT_ID_ALL_MAPPED) ? status[id].mappedPercent : 16, + percentValidated: (id === PROJECT_ID_ALL_VALIDATED) ? status[id].validatedPercent : 6, percentBadImagery: 0, aoiCentroid: { type: 'Point', @@ -73,7 +73,7 @@ export const getProjectSummary = (id) => ({ validationEditors: ['JOSM', 'POTLATCH_2', 'FIELD_PAPERS', 'ID'], }); -export const getProjectStats = (id) => ({ +export const getProjectStats = (id: string) => ({ projectId: Number(id), 'projectArea(in sq.km)': 3506.03997973834, totalMappers: 105, @@ -294,7 +294,7 @@ export const userTouchedProjects = { ], }; -export const taskDetail = (taskId) => ({ +export const taskDetail = (taskId: number) => ({ taskId: taskId, projectId: 5871, taskStatus: 'LOCKED_FOR_MAPPING', @@ -381,11 +381,11 @@ export const userFavorite = { favorited: false, }; -export const favoritePost = (id) => ({ +export const favoritePost = () => ({ project_id: 123, }); -export const activities = (id) => { +export const activities = (id: number) => { const isProjectValidated = id === PROJECT_ID_ALL_VALIDATED; return { activity: [ diff --git a/frontend/src/network/tests/mockData/taskGrid.js b/frontend/src/network/tests/mockData/taskGrid.ts similarity index 100% rename from frontend/src/network/tests/mockData/taskGrid.js rename to frontend/src/network/tests/mockData/taskGrid.ts diff --git a/frontend/src/network/tests/mockData/taskHistory.js b/frontend/src/network/tests/mockData/taskHistory.ts similarity index 100% rename from frontend/src/network/tests/mockData/taskHistory.js rename to frontend/src/network/tests/mockData/taskHistory.ts diff --git a/frontend/src/network/tests/mockData/tasksStats.js b/frontend/src/network/tests/mockData/tasksStats.ts similarity index 100% rename from frontend/src/network/tests/mockData/tasksStats.js rename to frontend/src/network/tests/mockData/tasksStats.ts diff --git a/frontend/src/network/tests/mockData/teams.js b/frontend/src/network/tests/mockData/teams.ts similarity index 100% rename from frontend/src/network/tests/mockData/teams.js rename to frontend/src/network/tests/mockData/teams.ts diff --git a/frontend/src/network/tests/mockData/userList.js b/frontend/src/network/tests/mockData/userList.ts similarity index 100% rename from frontend/src/network/tests/mockData/userList.js rename to frontend/src/network/tests/mockData/userList.ts diff --git a/frontend/src/network/tests/mockData/userStats.js b/frontend/src/network/tests/mockData/userStats.ts similarity index 100% rename from frontend/src/network/tests/mockData/userStats.js rename to frontend/src/network/tests/mockData/userStats.ts diff --git a/frontend/src/network/tests/server-handlers.js b/frontend/src/network/tests/server-handlers.ts similarity index 95% rename from frontend/src/network/tests/server-handlers.js rename to frontend/src/network/tests/server-handlers.ts index a17e768062..08769687eb 100644 --- a/frontend/src/network/tests/server-handlers.js +++ b/frontend/src/network/tests/server-handlers.ts @@ -1,4 +1,4 @@ -import { rest } from 'msw'; +import { DefaultBodyType, PathParams, ResponseComposition, rest, RestContext, RestRequest } from 'msw'; import { getProjectSummary, @@ -117,10 +117,12 @@ const handlers = [ return res(ctx.json(userFavorite)); }), rest.post(API_URL + 'projects/:id/favorite/', async (req, res, ctx) => { - return res(ctx.json(favoritePost(req.params.id))); + // return res(ctx.json(favoritePost(req.params.id))); + return res(ctx.json(favoritePost())); }), rest.get(API_URL + 'projects/:id/statistics/', async (req, res, ctx) => { const { id } = req.params; + // @ts-expect-error TS Migrations return res(ctx.json(getProjectStats(id))); }), rest.get(API_URL + 'projects/:id/contributions/queries/day/', async (req, res, ctx) => { @@ -299,14 +301,16 @@ const handlers = [ rest.get(API_URL + 'interests/:id/', (req, res, ctx) => { return res(ctx.json(interest)); }), - rest.patch(API_URL + 'interests/:id', (req, res, ctx) => { - return res(interestUpdationSuccess(req.body.name)); + rest.patch(API_URL + 'interests/:id', async (req, res, ctx) => { + const body = await req.json(); + return res(ctx.json(interestUpdationSuccess(body.name))); }), rest.delete(API_URL + 'interests/:id', (req, res, ctx) => { return res(ctx.json(interestDeletionSuccess)); }), - rest.post(API_URL + 'interests', (req, res, ctx) => { - return res(ctx.json(interestCreationSuccess(req.body.name))); + rest.post(API_URL + 'interests', async (req, res, ctx) => { + const body = await req.json(); + return res(ctx.json(interestCreationSuccess(body.name))); }), rest.get(API_URL + 'countries', (req, res, ctx) => { return res(ctx.json(countries)); @@ -375,7 +379,7 @@ const handlers = [ }), ]; -const failedToConnectError = (req, res, ctx) => { +const failedToConnectError = (_req: RestRequest>, res: ResponseComposition, _ctx: RestContext) => { return res.networkError('Failed to connect'); }; diff --git a/frontend/src/network/tests/server.js b/frontend/src/network/tests/server.ts similarity index 100% rename from frontend/src/network/tests/server.js rename to frontend/src/network/tests/server.ts diff --git a/frontend/src/network/user.js b/frontend/src/network/user.ts similarity index 64% rename from frontend/src/network/user.js rename to frontend/src/network/user.ts index f2f71c3386..0dbc3f9e20 100644 --- a/frontend/src/network/user.js +++ b/frontend/src/network/user.ts @@ -1,7 +1,7 @@ import { API_URL } from '../config'; -export function postNewUser(user) { - return fetch(`${API_URL}users/actions/register/`, { +export async function postNewUser(user: unknown) { + return await fetch(`${API_URL}users/actions/register/`, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/frontend/src/routes.js b/frontend/src/routes.tsx similarity index 100% rename from frontend/src/routes.js rename to frontend/src/routes.tsx diff --git a/frontend/src/service-worker.js b/frontend/src/service-worker.js index 527ba85f35..5d9df68021 100644 --- a/frontend/src/service-worker.js +++ b/frontend/src/service-worker.js @@ -47,7 +47,7 @@ registerRoute( return true; }, - createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html'), + createHandlerBoundToURL(import.meta.env.PUBLIC_URL + '/index.html'), ); // An example runtime caching route for requests that aren't handled by the diff --git a/frontend/src/serviceWorkerRegistration.js b/frontend/src/serviceWorkerRegistration.js index c0cc74e587..c961109121 100644 --- a/frontend/src/serviceWorkerRegistration.js +++ b/frontend/src/serviceWorkerRegistration.js @@ -12,16 +12,16 @@ const isLocalhost = Boolean( window.location.hostname === 'localhost' || - // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || - // 127.0.0.0/8 are considered localhost for IPv4. - window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/), + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.0/8 are considered localhost for IPv4. + window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/), ); export function register(config) { - if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + if (import.meta.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); + const publicUrl = new URL(import.meta.env.PUBLIC_URL, window.location.href); if (publicUrl.origin !== window.location.origin) { // Our service worker won't work if PUBLIC_URL is on a different origin // from what our page is served on. This might happen if a CDN is used to @@ -30,7 +30,7 @@ export function register(config) { } window.addEventListener('load', () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + const swUrl = `${import.meta.env.PUBLIC_URL}/service-worker.js`; if (isLocalhost) { // This is running on localhost. Let's check if a service worker still exists or not. @@ -41,7 +41,7 @@ export function register(config) { navigator.serviceWorker.ready.then(() => { console.log( 'This web app is being served cache-first by a service ' + - 'worker. To learn more, visit https://cra.link/PWA', + 'worker. To learn more, visit https://cra.link/PWA', ); }); } else { @@ -69,7 +69,7 @@ function registerValidSW(swUrl, config) { // content until all client tabs are closed. console.log( 'New content is available and will be used when all ' + - 'tabs for this page are closed. See https://cra.link/PWA.', + 'tabs for this page are closed. See https://cra.link/PWA.', ); // Execute callback diff --git a/frontend/src/store/actions/auth.js b/frontend/src/store/actions/auth.ts similarity index 54% rename from frontend/src/store/actions/auth.js rename to frontend/src/store/actions/auth.ts index ef38b19b94..46197fe5f1 100644 --- a/frontend/src/store/actions/auth.js +++ b/frontend/src/store/actions/auth.ts @@ -1,6 +1,8 @@ import { setItem, removeItem, getItem } from '../../utils/safe_storage'; import { pushToLocalJSONAPI, fetchLocalJSONAPI } from '../../network/genericJSONRequest'; import { setLoader } from './loader'; +import { Dispatch } from 'redux'; +import { RootStore } from '..'; export const types = { REGISTER_USER: 'REGISTER_USER', @@ -13,7 +15,7 @@ export const types = { SET_TOKEN: 'SET_TOKEN', SET_SESSION: 'SET_SESSION', CLEAR_SESSION: 'CLEAR_SESSION', -}; +} as const; export function clearUserDetails() { return { @@ -38,7 +40,7 @@ export const updateUserEmail = (userDetails, token, relevant_fields) => (dispatc }); }; -export const logout = () => (dispatch) => { +export const logout = () => (dispatch: Dispatch) => { removeItem('username'); removeItem('token'); removeItem('action'); @@ -89,7 +91,7 @@ export function updateSession(session) { }; } -export const setAuthDetails = (username, token, osm_oauth_token) => (dispatch) => { +export const setAuthDetails = (username: string, token: string, osm_oauth_token: string) => (dispatch: Dispatch) => { const encoded_token = btoa(token); setItem('token', encoded_token); setItem('username', username); @@ -105,53 +107,53 @@ export const setAuthDetails = (username, token, osm_oauth_token) => (dispatch) = // UPDATES OSM INFORMATION OF THE USER export const setUserDetails = - (username, encodedToken, update = false) => - (dispatch) => { - // only trigger the loader if this function is not being triggered to update the user information - if (!update) dispatch(setLoader(true)); - fetchLocalJSONAPI(`users/${username}/openstreetmap/`, encodedToken) - .then((osmInfo) => dispatch(updateOSMInfo(osmInfo))) - .catch((error) => { - console.log(error); - dispatch(setLoader(false)); - }); - // GET USER DETAILS - fetchLocalJSONAPI(`users/queries/${username}/`, encodedToken) - .then((userDetails) => { - dispatch(updateUserDetails(userDetails)); - // GET USER ORGS INFO - fetchLocalJSONAPI( - `organisations/?omitManagerList=true&manager_user_id=${userDetails.id}`, - encodedToken, - ) - .then((orgs) => - dispatch(updateOrgsInfo(orgs.organisations.map((org) => org.organisationId))), + (username: string, encodedToken: string, update: boolean = false) => + (dispatch: Dispatch) => { + // only trigger the loader if this function is not being triggered to update the user information + if (!update) dispatch(setLoader(true)); + fetchLocalJSONAPI(`users/${username}/openstreetmap/`, encodedToken) + .then((osmInfo) => dispatch(updateOSMInfo(osmInfo))) + .catch((error) => { + console.log(error); + dispatch(setLoader(false)); + }); + // GET USER DETAILS + fetchLocalJSONAPI(`users/queries/${username}/`, encodedToken) + .then((userDetails) => { + dispatch(updateUserDetails(userDetails)); + // GET USER ORGS INFO + fetchLocalJSONAPI( + `organisations/?omitManagerList=true&manager_user_id=${userDetails.id}`, + encodedToken, ) - .catch((error) => dispatch(updateOrgsInfo([]))); - fetchLocalJSONAPI( - `teams/?omitMemberList=true&team_role=PROJECT_MANAGER&member=${userDetails.id}`, - encodedToken, - ) - .then((teams) => dispatch(updatePMsTeams(teams.teams.map((team) => team.teamId)))) - .catch((error) => dispatch(updatePMsTeams([]))); - dispatch(setLoader(false)); - }) - .catch((error) => { - if (error.message === 'InvalidToken') dispatch(logout()); - dispatch(setLoader(false)); - }); - }; + .then((orgs) => + dispatch(updateOrgsInfo(orgs.organisations.map((org) => org.organisationId))), + ) + .catch((error) => dispatch(updateOrgsInfo([]))); + fetchLocalJSONAPI( + `teams/?omitMemberList=true&team_role=PROJECT_MANAGER&member=${userDetails.id}`, + encodedToken, + ) + .then((teams) => dispatch(updatePMsTeams(teams.teams.map((team) => team.teamId)))) + .catch((error) => dispatch(updatePMsTeams([]))); + dispatch(setLoader(false)); + }) + .catch((error) => { + if (error.message === 'InvalidToken') dispatch(logout()); + dispatch(setLoader(false)); + }); + }; -export const getUserDetails = (state) => (dispatch) => { - if (state.auth.userDetails.username) { +export const getUserDetails = (state: RootStore) => (dispatch: Dispatch) => { + if (state.auth.userDetails?.username) { dispatch(setUserDetails(state.auth.userDetails.username, state.auth.token)); } }; export const pushUserDetails = (userDetails, token, update = false) => - (dispatch) => { - pushToLocalJSONAPI(`users/me/actions/set-user/`, userDetails, token, 'PATCH').then((data) => - dispatch(setUserDetails(getItem('username'), token, update)), - ); - }; + (dispatch) => { + pushToLocalJSONAPI(`users/me/actions/set-user/`, userDetails, token, 'PATCH').then((data) => + dispatch(setUserDetails(getItem('username'), token, update)), + ); + }; diff --git a/frontend/src/store/actions/editor.js b/frontend/src/store/actions/editor.ts similarity index 88% rename from frontend/src/store/actions/editor.js rename to frontend/src/store/actions/editor.ts index cae5b7376f..7784e83d3a 100644 --- a/frontend/src/store/actions/editor.js +++ b/frontend/src/store/actions/editor.ts @@ -1,4 +1,4 @@ export const types = { SET_EDITOR: 'SET_EDITOR', SET_RAPIDEDITOR: 'SET_RAPIDEDITOR', -}; +} as const; diff --git a/frontend/src/store/actions/loader.js b/frontend/src/store/actions/loader.ts similarity index 67% rename from frontend/src/store/actions/loader.js rename to frontend/src/store/actions/loader.ts index 8c44e9343c..0c1588319b 100644 --- a/frontend/src/store/actions/loader.js +++ b/frontend/src/store/actions/loader.ts @@ -1,8 +1,8 @@ export const types = { SET_LOADER: 'SET_LOADER', -}; +} as const; -export function setLoader(isLoading) { +export function setLoader(isLoading: boolean) { return { type: types.SET_LOADER, isLoading: isLoading, diff --git a/frontend/src/store/actions/notifications.js b/frontend/src/store/actions/notifications.ts similarity index 95% rename from frontend/src/store/actions/notifications.js rename to frontend/src/store/actions/notifications.ts index de011f3e57..a0b6f30ae4 100644 --- a/frontend/src/store/actions/notifications.js +++ b/frontend/src/store/actions/notifications.ts @@ -4,4 +4,4 @@ export const types = { NOTIFICATIONS_FAILURE: 'NOTIFICATIONS_FAILURE', SET_UNREAD_COUNT: 'SET_UNREAD_COUNT', DECREMENT_UNREAD_COUNT: 'DECREMENT_UNREAD_COUNT', -}; +} as const; diff --git a/frontend/src/store/actions/project.js b/frontend/src/store/actions/project.ts similarity index 66% rename from frontend/src/store/actions/project.js rename to frontend/src/store/actions/project.ts index a6bec46e4b..731a99c124 100644 --- a/frontend/src/store/actions/project.js +++ b/frontend/src/store/actions/project.ts @@ -1,9 +1,11 @@ +import { Dispatch } from "redux"; + export const types = { CREATE_PROJECT: 'CREATE_PROJECT', SET_ID: 'SET_ID', -}; +} as const; -export const createProject = (params) => (dispatch) => { +export const createProject = (params: any) => (dispatch: Dispatch) => { const dispatch_params = { type: types.CREATE_PROJECT, params: params, diff --git a/frontend/src/store/actions/tasks.js b/frontend/src/store/actions/tasks.ts similarity index 64% rename from frontend/src/store/actions/tasks.js rename to frontend/src/store/actions/tasks.ts index 91835e81c0..81f0f18862 100644 --- a/frontend/src/store/actions/tasks.js +++ b/frontend/src/store/actions/tasks.ts @@ -1,25 +1,27 @@ +import { Dispatch } from "redux"; + export const types = { SET_LOCKED_TASKS: 'SET_LOCKED_TASKS', SET_PROJECT: 'SET_PROJECT', SET_TASKS_STATUS: 'SET_TASKS_STATUS', CLEAR_LOCKED_TASKS: 'CLEAR_LOCKED_TASKS', -}; +} as const; -export function updateProject(project) { +export function updateProject(project: any) { return { type: types.SET_PROJECT, project: project, }; } -export function updateLockedTasks(tasks) { +export function updateLockedTasks(tasks: any) { return { type: types.SET_LOCKED_TASKS, tasks: tasks, }; } -export function updateTasksStatus(status) { +export function updateTasksStatus(status: any) { return { type: types.SET_TASKS_STATUS, status: status, @@ -32,11 +34,11 @@ export function clearLockedTasks() { }; } -export const setLockedTasks = (tasks, projectId) => (dispatch) => { +export const setLockedTasks = (tasks, projectId) => (dispatch: Dispatch) => { dispatch(updateLockedTasks(tasks)); dispatch(updateProject(projectId)); }; -export const setTasksStatus = (status) => (dispatch) => { +export const setTasksStatus = (status) => (dispatch: Dispatch) => { dispatch(updateTasksStatus(status)); }; diff --git a/frontend/src/store/actions/user.js b/frontend/src/store/actions/user.ts similarity index 64% rename from frontend/src/store/actions/user.js rename to frontend/src/store/actions/user.ts index e493cf2e8a..c0f41aaeba 100644 --- a/frontend/src/store/actions/user.js +++ b/frontend/src/store/actions/user.ts @@ -1,9 +1,10 @@ import { setItem } from '../../utils/safe_storage'; import { postNewUser } from '../../network/user'; import { types } from './auth'; +import { Dispatch } from 'redux'; -export const registerUser = (postData) => (dispatch) => { - return postNewUser(postData).then((res) => { +export const registerUser = (postData: unknown) => async (dispatch: Dispatch) => { + return await postNewUser(postData).then((res) => { if (res.success === true) { setItem('userId', res.id); } diff --git a/frontend/src/store/actions/userPreferences.js b/frontend/src/store/actions/userPreferences.ts similarity index 69% rename from frontend/src/store/actions/userPreferences.js rename to frontend/src/store/actions/userPreferences.ts index f7995c303b..68994d79bc 100644 --- a/frontend/src/store/actions/userPreferences.js +++ b/frontend/src/store/actions/userPreferences.ts @@ -1,3 +1,4 @@ +import { Dispatch } from 'redux'; import { setItem } from '../../utils/safe_storage'; export const types = { @@ -6,16 +7,16 @@ export const types = { TOGGLE_MAP: 'TOGGLE_MAP', TOGGLE_LIST_VIEW: 'TOGGLE_LIST_VIEW', TOGGLE_CARD_VIEW: 'TOGGLE_CARD_VIEW', -}; +} as const; -export function updateLocale(locale) { +export function updateLocale(locale: string) { return { type: types.SET_LOCALE, locale: locale, }; } -export const setLocale = (locale) => (dispatch) => { +export const setLocale = (locale: string) => (dispatch: Dispatch) => { setItem('locale', locale); dispatch(updateLocale(locale)); }; diff --git a/frontend/src/store/index.js b/frontend/src/store/index.ts similarity index 52% rename from frontend/src/store/index.js rename to frontend/src/store/index.ts index 3e798a3fdd..3c120072fa 100644 --- a/frontend/src/store/index.js +++ b/frontend/src/store/index.ts @@ -6,6 +6,7 @@ import storage from 'redux-persist/lib/storage'; import { setItem } from '../utils/safe_storage'; import reducers from './reducers'; +import { composeWithDevTools } from '@redux-devtools/extension'; const persistConfig = { key: 'root', @@ -15,22 +16,16 @@ const persistConfig = { const persistedReducer = persistReducer(persistConfig, reducers); -const enhancers = []; +const store = createStore(persistedReducer, undefined, composeWithDevTools((applyMiddleware(thunk)))); -const composeEnhancers = - (process.env.NODE_ENV === 'development' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || - compose; - -const composedEnhancers = composeEnhancers(applyMiddleware(thunk), ...enhancers); - -const store = createStore(persistedReducer, {}, composedEnhancers); +export type RootStore = ReturnType; const persistor = persistStore(store); store.subscribe(() => { - setItem('mapShown', store.getState().preferences['mapShown']); - setItem('action', store.getState().preferences['action']); - setItem('projectListView', store.getState().preferences['projectListView']); + setItem('mapShown', store.getState().preferences.mapShown); + setItem('action', store.getState().preferences.action); + setItem('projectListView', store.getState().preferences.projectListView); }); export { store, persistor }; diff --git a/frontend/src/store/reducers/auth.js b/frontend/src/store/reducers/auth.js deleted file mode 100644 index 30656f6b40..0000000000 --- a/frontend/src/store/reducers/auth.js +++ /dev/null @@ -1,38 +0,0 @@ -import { types } from '../actions/auth'; - -const initialState = { - userDetails: {}, - token: '', - session: {}, - osm: {}, - organisations: [], - pmTeams: [], -}; - -export function authorizationReducer(state = initialState, action) { - switch (action.type) { - case types.SET_USER_DETAILS: { - return { ...state, userDetails: action.userDetails }; - } - case types.SET_OSM: { - return { ...state, osm: action.osm }; - } - case types.SET_ORGANISATIONS: { - return { ...state, organisations: action.organisations }; - } - case types.SET_PM_TEAMS: { - return { ...state, pmTeams: action.teams }; - } - case types.SET_TOKEN: { - return { ...state, token: action.token }; - } - case types.SET_SESSION: { - return { ...state, session: action.session }; - } - case types.CLEAR_SESSION: { - return initialState; - } - default: - return state; - } -} diff --git a/frontend/src/store/reducers/auth.ts b/frontend/src/store/reducers/auth.ts new file mode 100644 index 0000000000..4817374d27 --- /dev/null +++ b/frontend/src/store/reducers/auth.ts @@ -0,0 +1,80 @@ +import { types } from '../actions/auth'; + +type UserData = { + userDetails: { + id: number; + username: string; + emailAddress: string; + role: string; + pictureUrl: string; + } | null, + token: string, + session: { + osm_oauth_token: string; + } | null, + osm: { + accountCreated: string; + } | null, + organisations: string[], + pmTeams: string[], +} + +const initialState = { + userDetails: null, + token: '', + session: null, + osm: null, + organisations: [], + pmTeams: [], +} satisfies UserData; + +type Actions = { + type: typeof types.SET_USER_DETAILS, + userDetails: UserData['userDetails'], +} | { + type: typeof types.SET_OSM, + osm: UserData['osm'], +} | { + type: typeof types.SET_ORGANISATIONS, + organisations: UserData['organisations'], +} | { + type: typeof types.SET_PM_TEAMS, + teams: UserData['pmTeams'], +} | { + type: typeof types.SET_TOKEN, + token: UserData['token'], +} | { + type: typeof types.SET_SESSION, + session: UserData['session'], +} | { + type: typeof types.CLEAR_SESSION, + session: null, +} + +export function authorizationReducer(state: UserData = initialState, action: Actions): UserData { + switch (action.type) { + case types.SET_USER_DETAILS: { + return { ...state, userDetails: action.userDetails }; + } + case types.SET_OSM: { + return { ...state, osm: action.osm }; + } + case types.SET_ORGANISATIONS: { + return { ...state, organisations: action.organisations }; + } + case types.SET_PM_TEAMS: { + return { ...state, pmTeams: action.teams }; + } + case types.SET_TOKEN: { + return { ...state, token: action.token }; + } + case types.SET_SESSION: { + return { ...state, session: action.session }; + } + case types.CLEAR_SESSION: { + return initialState; + } + default: + return state; + } +} diff --git a/frontend/src/store/reducers/editor.js b/frontend/src/store/reducers/editor.ts similarity index 56% rename from frontend/src/store/reducers/editor.js rename to frontend/src/store/reducers/editor.ts index 7f428b676b..e0a38fafbe 100644 --- a/frontend/src/store/reducers/editor.js +++ b/frontend/src/store/reducers/editor.ts @@ -1,11 +1,24 @@ import { types } from '../actions/editor'; +type EditorState = { + context: any; + rapidContext: { context: any; dom: any }; +}; + const initialState = { context: null, rapidContext: { context: null, dom: null }, -}; +} satisfies EditorState; + +type Actions = { + type: typeof types.SET_EDITOR; + context: any; +} | { + type: typeof types.SET_RAPIDEDITOR; + context: { context: any; dom: any }; +} -export function editorReducer(state = initialState, action) { +export function editorReducer(state = initialState, action: Actions) { switch (action.type) { case types.SET_EDITOR: { return { diff --git a/frontend/src/store/reducers/index.js b/frontend/src/store/reducers/index.ts similarity index 92% rename from frontend/src/store/reducers/index.js rename to frontend/src/store/reducers/index.ts index 67c0203dd9..505ecdb1c0 100644 --- a/frontend/src/store/reducers/index.js +++ b/frontend/src/store/reducers/index.ts @@ -10,7 +10,7 @@ import { loaderReducer } from './loader'; import { editorReducer } from './editor'; import { orgBarVisibilityReducer } from './orgTopBar'; -export default combineReducers({ +const reducers = combineReducers({ preferences: preferencesReducer, auth: authorizationReducer, notifications: notificationsReducer, @@ -21,3 +21,5 @@ export default combineReducers({ editor: editorReducer, orgBarVisibility: orgBarVisibilityReducer, }); + +export default reducers; diff --git a/frontend/src/store/reducers/loader.js b/frontend/src/store/reducers/loader.ts similarity index 52% rename from frontend/src/store/reducers/loader.js rename to frontend/src/store/reducers/loader.ts index 6e1675cade..2484edd857 100644 --- a/frontend/src/store/reducers/loader.js +++ b/frontend/src/store/reducers/loader.ts @@ -2,9 +2,18 @@ import { types } from '../actions/loader'; const initialState = { isLoading: false, -}; +} satisfies { isLoading: boolean; }; -export function loaderReducer(state = initialState, action) { +type Actions = { + type: typeof types.SET_LOADER; + isLoading: boolean; +} + +export function loaderReducer(state: { + isLoading: boolean; +} = initialState, action: Actions): { + isLoading: boolean; +} { switch (action.type) { case types.SET_LOADER: { return { diff --git a/frontend/src/store/reducers/notifications.js b/frontend/src/store/reducers/notifications.ts similarity index 52% rename from frontend/src/store/reducers/notifications.js rename to frontend/src/store/reducers/notifications.ts index da05d9e5dc..5504d0e468 100644 --- a/frontend/src/store/reducers/notifications.js +++ b/frontend/src/store/reducers/notifications.ts @@ -1,12 +1,52 @@ import { types } from '../actions/notifications'; +type Notification = { + notifications: any[]; + userMessages: any[]; + isLoading: boolean; + isFirstLoading: boolean; + isError: boolean; + unreadNotificationsMini: any[]; + lastParams: any; + pagination: { hasNext: boolean; hasPrev: boolean; page: number }; + unreadCount: number; + params: { + status: string; + } +}; + const initialState = { notifications: [], + userMessages: [], + unreadNotificationsMini: [], + isLoading: false, + isFirstLoading: false, + isError: false, + lastParams: {}, pagination: { hasNext: false, hasPrev: false, page: 1 }, - unreadCount: null, + unreadCount: 0, + params: { + status: "" + } +} satisfies Notification; + +type Actions = { + type: typeof types.NOTIFICATIONS_INIT; +} | { + type: typeof types.NOTIFICATIONS_SUCCESS; + userMessages: any[]; + pagination: Notification["pagination"] + params: any; +} | { + type: typeof types.NOTIFICATIONS_FAILURE; +} | { + type: typeof types.SET_UNREAD_COUNT; + payload: number; +} | { + type: typeof types.DECREMENT_UNREAD_COUNT; }; -export const notificationsReducer = (state = initialState, action) => { +export const notificationsReducer = (state: Notification = initialState, action: Actions): Notification => { switch (action.type) { case types.NOTIFICATIONS_INIT: return { @@ -16,14 +56,14 @@ export const notificationsReducer = (state = initialState, action) => { isError: false, }; case types.NOTIFICATIONS_SUCCESS: - const pagedNotifs = action.payload.userMessages.map((n) => ({ + const pagedNotifs = action.userMessages.map((n) => ({ ...n, - page: action.payload.pagination.page, + page: action.pagination.page, })); const goodForMiniResults = action.params['status'] && action.params['status'] === 'unread' && - action.payload.pagination.page === 1; + action.pagination.page === 1; return { ...state, @@ -34,7 +74,7 @@ export const notificationsReducer = (state = initialState, action) => { lastParams: action.params, unreadNotificationsMini: (goodForMiniResults && pagedNotifs) || state.unreadNotificationsMini, - pagination: action.payload.pagination, + pagination: action.pagination, }; case types.NOTIFICATIONS_FAILURE: return { diff --git a/frontend/src/store/reducers/orgTopBar.js b/frontend/src/store/reducers/orgTopBar.ts similarity index 51% rename from frontend/src/store/reducers/orgTopBar.js rename to frontend/src/store/reducers/orgTopBar.ts index c8845908df..051e6e203e 100644 --- a/frontend/src/store/reducers/orgTopBar.js +++ b/frontend/src/store/reducers/orgTopBar.ts @@ -1,8 +1,17 @@ const initialState = { isVisible: true, +} satisfies { + isVisible: boolean; }; -export function orgBarVisibilityReducer(state = initialState, action) { +type Actions = { + type: 'SET_VISIBILITY'; + isVisible: boolean; +} + +export function orgBarVisibilityReducer(state: { + isVisible: boolean; +} = initialState, action: Actions) { switch (action.type) { case 'SET_VISIBILITY': { return { diff --git a/frontend/src/store/reducers/project.js b/frontend/src/store/reducers/project.ts similarity index 53% rename from frontend/src/store/reducers/project.js rename to frontend/src/store/reducers/project.ts index 7d64b37035..8b0617bfa1 100644 --- a/frontend/src/store/reducers/project.js +++ b/frontend/src/store/reducers/project.ts @@ -1,11 +1,24 @@ import { types } from '../actions/project'; +type ProjectState = { + projectId: string | null, + params: any, +}; + const initialState = { projectId: null, params: {}, +} satisfies ProjectState; + +type Actions = { + type: typeof types.CREATE_PROJECT + params: any +} | { + type: typeof types.SET_ID, + projectId: string }; -export function projectReducer(state = initialState, action) { +export function projectReducer(state: ProjectState = initialState, action: Actions) { switch (action.type) { case types.CREATE_PROJECT: { return { ...state, params: action.params }; diff --git a/frontend/src/store/reducers/tasks.js b/frontend/src/store/reducers/tasks.ts similarity index 50% rename from frontend/src/store/reducers/tasks.js rename to frontend/src/store/reducers/tasks.ts index ad7c3b5a20..fe3491fb67 100644 --- a/frontend/src/store/reducers/tasks.js +++ b/frontend/src/store/reducers/tasks.ts @@ -1,12 +1,36 @@ import { types } from '../actions/tasks'; +type TaskData = { + tasks: { + taskId: string; + title: string; + projectId: string; + status: string; + }[], + status: string | null, + project: any +} + const initialState = { project: null, tasks: [], status: null, -}; +} satisfies TaskData; + +type Actions = { + type: typeof types.SET_PROJECT, + project: any +} | { + type: typeof types.SET_LOCKED_TASKS, + tasks: any +} | { + type: typeof types.SET_TASKS_STATUS, + status: string +} | { + type: typeof types.CLEAR_LOCKED_TASKS +} -export function tasksReducer(state = initialState, action) { +export function tasksReducer(state: TaskData = initialState, action: Actions): TaskData { switch (action.type) { case types.SET_PROJECT: { return { ...state, project: action.project }; diff --git a/frontend/src/store/reducers/user.js b/frontend/src/store/reducers/user.ts similarity index 53% rename from frontend/src/store/reducers/user.js rename to frontend/src/store/reducers/user.ts index dc376ec31f..d994a19965 100644 --- a/frontend/src/store/reducers/user.js +++ b/frontend/src/store/reducers/user.ts @@ -1,5 +1,14 @@ import { types } from '../actions/auth'; +type User = { + user: { + email: string; + success: boolean; + details: string; + id: number; + } +}; + const initialState = { user: { email: '', @@ -7,9 +16,14 @@ const initialState = { details: '', id: 0, }, +} satisfies User; + +type Actions = { + type: typeof types.REGISTER_USER, + payload: User['user'], }; -export function userReducer(state = initialState, action) { +export function userReducer(state: User = initialState, action: Actions) { switch (action.type) { case types.REGISTER_USER: { return { diff --git a/frontend/src/store/reducers/userPreferences.js b/frontend/src/store/reducers/userPreferences.ts similarity index 56% rename from frontend/src/store/reducers/userPreferences.js rename to frontend/src/store/reducers/userPreferences.ts index 1bf1ea1394..095d8d0841 100644 --- a/frontend/src/store/reducers/userPreferences.js +++ b/frontend/src/store/reducers/userPreferences.ts @@ -1,13 +1,37 @@ import { types } from '../actions/userPreferences'; +type UserPreferences = { + locale: string, + mapShown: boolean, + projectListView: boolean, + action: string, +} + const initialState = { - locale: null, + locale: "en", mapShown: false, projectListView: false, action: 'any', -}; +} satisfies UserPreferences; + +type Actions = { + type: typeof types.SET_LOCALE; + locale: string; +} | { + type: typeof types.SET_ACTION; + action: string; +} | { + type: typeof types.TOGGLE_MAP; + mapShown: boolean; +} | { + type: typeof types.TOGGLE_LIST_VIEW; + projectListView: boolean; +} | { + type: typeof types.TOGGLE_CARD_VIEW; + projectListView: boolean; +} -export function preferencesReducer(state = initialState, action) { +export function preferencesReducer(state: UserPreferences = initialState, action: Actions) { switch (action.type) { case types.SET_LOCALE: { return { diff --git a/frontend/src/utils/CommaArrayParam.js b/frontend/src/utils/CommaArrayParam.ts similarity index 100% rename from frontend/src/utils/CommaArrayParam.js rename to frontend/src/utils/CommaArrayParam.ts diff --git a/frontend/src/utils/chart.js b/frontend/src/utils/chart.ts similarity index 50% rename from frontend/src/utils/chart.js rename to frontend/src/utils/chart.ts index 29f9e472da..3974ea2b86 100644 --- a/frontend/src/utils/chart.js +++ b/frontend/src/utils/chart.ts @@ -1,24 +1,20 @@ import { enUS } from 'date-fns/locale'; import { formatISO } from 'date-fns'; -/** - * x axis configuration common between this and {@link ../projectDetail/timeline.js} - * @param unit The base unit for the axis - * @typedef {import('chart.js').ScaleOptionsByType} ScaleOptionsByType - * @returns {ScaleOptionsByType} The options to use for x axis configuration - */ -function xAxisTimeSeries(unit) { +import type { ScaleOptionsByType, TimeUnit } from "chart.js"; + +function xAxisTimeSeries(unit: TimeUnit) { return { type: 'timeseries', adapters: { date: { locale: enUS } }, time: { unit: unit, - tooltipFormat: enUS.formatLong.date, + tooltipFormat: enUS.formatLong.date({}), }, ticks: { source: 'labels', callback: (value, index, ticks) => formatISO(ticks[index].value, { representation: 'date' }), }, - }; + } satisfies ScaleOptionsByType; } export { xAxisTimeSeries }; diff --git a/frontend/src/utils/date.js b/frontend/src/utils/date.ts similarity index 96% rename from frontend/src/utils/date.js rename to frontend/src/utils/date.ts index 1ab5170b51..865035b439 100644 --- a/frontend/src/utils/date.js +++ b/frontend/src/utils/date.ts @@ -8,7 +8,7 @@ import { endOfYear, } from 'date-fns'; -export function getPastMonths(months) { +export function getPastMonths(months: number) { let today = new Date(); return today.setMonth(today.getMonth() - months); } diff --git a/frontend/src/utils/formatChartJSData.js b/frontend/src/utils/formatChartJSData.ts similarity index 83% rename from frontend/src/utils/formatChartJSData.js rename to frontend/src/utils/formatChartJSData.ts index b352de49c6..2b48418094 100644 --- a/frontend/src/utils/formatChartJSData.js +++ b/frontend/src/utils/formatChartJSData.ts @@ -1,4 +1,4 @@ -export const formatChartData = (reference, stats) => { +export const formatChartData = (reference: any, stats: any) => { let data = { datasets: [{ data: [], backgroundColor: [] }], labels: [] }; data.datasets[0].data = reference.map((f) => stats[f.field]); @@ -11,7 +11,7 @@ export const formatChartData = (reference, stats) => { return data; }; -export const formatTimelineData = (stats, mappedTasksConfig, validatedTasksConfig) => { +export const formatTimelineData = (stats: any, mappedTasksConfig: any, validatedTasksConfig: any) => { let mapped = { data: [], backgroundColor: mappedTasksConfig.color, @@ -38,7 +38,7 @@ export const formatTimelineData = (stats, mappedTasksConfig, validatedTasksConfi return { datasets: [validated, mapped], labels: labels }; }; -export const formatTasksStatsData = (stats, mappedTasksConfig, validatedTasksConfig) => { +export const formatTasksStatsData = (stats: any, mappedTasksConfig: any, validatedTasksConfig: any) => { let mapped = { data: [], backgroundColor: mappedTasksConfig.color, @@ -57,7 +57,7 @@ export const formatTasksStatsData = (stats, mappedTasksConfig, validatedTasksCon return { datasets: [mapped, validated], labels: labels }; }; -export const formatTooltip = (context) => { +export const formatTooltip = (context: any) => { var label = context.label; if (label) label += ': '; label += context.dataset.data[context.dataIndex]; @@ -65,7 +65,7 @@ export const formatTooltip = (context) => { return `${label}%`; }; -export const formatTimelineTooltip = (context, isPercent) => { +export const formatTimelineTooltip = (context: any, isPercent: boolean) => { var label = context.dataset.label || ''; if (label) label += ': '; label += context.dataset.data[context.dataIndex]; diff --git a/frontend/src/utils/formattedRelativeTime.js b/frontend/src/utils/formattedRelativeTime.tsx similarity index 70% rename from frontend/src/utils/formattedRelativeTime.js rename to frontend/src/utils/formattedRelativeTime.tsx index 58cfd3b1ed..dd24432d86 100644 --- a/frontend/src/utils/formattedRelativeTime.js +++ b/frontend/src/utils/formattedRelativeTime.tsx @@ -2,7 +2,9 @@ import { FormattedRelativeTime } from 'react-intl'; import { selectUnit } from './selectUnit'; -export const RelativeTimeWithUnit = ({ date }) => { +export const RelativeTimeWithUnit = ({ date }: { + date: string | number | Date; +}) => { const { value, unit } = selectUnit(new Date(date)); return ; diff --git a/frontend/src/utils/htmlFromMarkdown.js b/frontend/src/utils/htmlFromMarkdown.ts similarity index 90% rename from frontend/src/utils/htmlFromMarkdown.js rename to frontend/src/utils/htmlFromMarkdown.ts index 5f2ef5acf8..c9ef02c66c 100644 --- a/frontend/src/utils/htmlFromMarkdown.js +++ b/frontend/src/utils/htmlFromMarkdown.ts @@ -3,7 +3,7 @@ import DOMPurify from 'dompurify'; const VIDEO_TAG_REGEXP = new RegExp(/^::youtube\[(.*)\]$/); -const parseMarkdown = (markdownText) => { +const parseMarkdown = async (markdownText: string) => { marked.use({ gfm: false, extensions: [ @@ -47,11 +47,11 @@ const parseMarkdown = (markdownText) => { }, ], }); - return marked.parse(markdownText); + return await marked.parse(markdownText); }; /* per https://stackoverflow.com/a/34688574/272018 */ -export const htmlFromMarkdown = (markdownText) => { +export const htmlFromMarkdown = async (markdownText: string) => { DOMPurify.addHook('afterSanitizeAttributes', function (node) { // set all elements owning target to target=_blank if ('target' in node) { @@ -81,10 +81,10 @@ export const htmlFromMarkdown = (markdownText) => { ADD_ATTR: ['allow', 'allowfullscreen', 'frameborder'], }; - return { __html: DOMPurify.sanitize(parseMarkdown(markdownText), config) }; + return { __html: DOMPurify.sanitize(await parseMarkdown(markdownText), config) }; }; -export const formatUserNamesToLink = (text) => { +export const formatUserNamesToLink = (text: string) => { const regex = /@\[([^\]]+)\]/gi; // Find usernames with a regular expression. They all start with '[@' and end with ']' const usernames = text && text.match(regex); diff --git a/frontend/src/utils/internationalization.js b/frontend/src/utils/internationalization.jsx similarity index 100% rename from frontend/src/utils/internationalization.js rename to frontend/src/utils/internationalization.jsx diff --git a/frontend/src/utils/login.js b/frontend/src/utils/login.ts similarity index 100% rename from frontend/src/utils/login.js rename to frontend/src/utils/login.ts diff --git a/frontend/src/utils/promise.js b/frontend/src/utils/promise.ts similarity index 91% rename from frontend/src/utils/promise.js rename to frontend/src/utils/promise.ts index a9af63507a..81208988b2 100644 --- a/frontend/src/utils/promise.js +++ b/frontend/src/utils/promise.ts @@ -1,4 +1,4 @@ -export function cancelablePromise(promise: Promise<*>) { +export function cancelablePromise(promise: Promise) { let hasCanceled_ = false; const wrappedPromise = new Promise((resolve, reject) => { @@ -39,6 +39,6 @@ export function cancelableFetchJSON(url: string) { ); } -export function delayPromise(interval: number): { promise: Promise<*>, cancel: () => any } { +export function delayPromise(interval: number): { promise: Promise, cancel: () => any } { return cancelablePromise(new Promise((res) => setTimeout(res, interval))); } diff --git a/frontend/src/utils/random.js b/frontend/src/utils/random.ts similarity index 65% rename from frontend/src/utils/random.js rename to frontend/src/utils/random.ts index adc5c6a557..e35e66aaa7 100644 --- a/frontend/src/utils/random.js +++ b/frontend/src/utils/random.ts @@ -1,9 +1,9 @@ -export function getRandomInt(min, max) { +export function getRandomInt(min: number, max: number) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive } -export function getRandomArrayItem(arr) { +export function getRandomArrayItem(arr: unknown[]) { return arr[getRandomInt(0, arr.length)]; } diff --git a/frontend/src/utils/remapParamsToAPI.js b/frontend/src/utils/remapParamsToAPI.ts similarity index 78% rename from frontend/src/utils/remapParamsToAPI.js rename to frontend/src/utils/remapParamsToAPI.ts index ba1df405fc..c0c3e311cc 100644 --- a/frontend/src/utils/remapParamsToAPI.js +++ b/frontend/src/utils/remapParamsToAPI.ts @@ -1,4 +1,4 @@ -const fromEntries = require('fromentries'); +import fromEntries from "fromentries" /* read about it at MDN's Object.fromEntries – this is a tiny polyfill/ponyfill. /* The API uses slightly different JSON keys than the queryParams, @@ -8,9 +8,10 @@ const fromEntries = require('fromentries'); left key is client query param, right value is what backend calls the parameter */ -export const remapParamsToAPI = (param, conversion) => { - function mapObject(obj, fn) { +export const remapParamsToAPI = (param: unknown, conversion: unknown) => { + function mapObject(obj: unknown, fn: (n: any) => void) { /* like Object.fromEntries */ + // @ts-expect-error TS migration return fromEntries(Object.entries(obj).map(fn)); } const remapped = mapObject(param, (n) => { diff --git a/frontend/src/utils/safe_storage.js b/frontend/src/utils/safe_storage.ts similarity index 73% rename from frontend/src/utils/safe_storage.js rename to frontend/src/utils/safe_storage.ts index 761da61f7f..0bee4dab0a 100644 --- a/frontend/src/utils/safe_storage.js +++ b/frontend/src/utils/safe_storage.ts @@ -6,9 +6,13 @@ * Wraps localStorage.getItem in a try/catch. Return null * if the key does not exist or localStorage fails. */ -function getItem(key: string): ?string { +function getItem(key: string) { try { - return localStorage.getItem(key) || null; + const gotKey = localStorage.getItem(key); + if (gotKey === null) { + return null; + } + return JSON.parse(gotKey) as unknown; } catch (err) { console.warn('Could not read from localStorage.'); return null; @@ -18,9 +22,9 @@ function getItem(key: string): ?string { /** * Wraps localStorage.setItem in a try/catch. */ -function setItem(key: string, value: string): void { +function setItem(key: string, value: unknown): void { try { - localStorage.setItem(key, value); + localStorage.setItem(key, JSON.stringify(value)); } catch (err) { console.warn('Could not write to localStorage.'); } diff --git a/frontend/src/utils/selectUnit.js b/frontend/src/utils/selectUnit.ts similarity index 81% rename from frontend/src/utils/selectUnit.js rename to frontend/src/utils/selectUnit.ts index a40ef56989..39da06b165 100644 --- a/frontend/src/utils/selectUnit.js +++ b/frontend/src/utils/selectUnit.ts @@ -1,10 +1,15 @@ // this code is an adaptation of https://www.npmjs.com/package/@formatjs/intl-utils -var __assign = +import { FormattedRelativeTime } from "react-intl"; + +let __assign = + // @ts-expect-error TS Migrations (this && this.__assign) || function () { + // @ts-expect-error TS Migrations __assign = Object.assign || + // @ts-expect-error TS Migrations function (t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; @@ -27,13 +32,18 @@ const DEFAULT_THRESHOLDS = { day: 7, }; -export function selectUnit(from, to, thresholds) { +export function selectUnit(from: Date | number, to: Date | number = Date.now(), thresholds = DEFAULT_THRESHOLDS): { + value: number; + unit: Parameters["0"]["unit"] +} { if (to === void 0) { to = Date.now(); } if (thresholds === void 0) { + // @ts-expect-error TS Migrations thresholds = {}; } + // @ts-expect-error TS Migrations const resolvedThresholds = __assign(__assign({}, DEFAULT_THRESHOLDS), thresholds || {}); const secs = (+from - +to) / MS_PER_SECOND; if (Math.abs(secs) < resolvedThresholds.second) { diff --git a/frontend/src/utils/slugifyFileName.js b/frontend/src/utils/slugifyFileName.ts similarity index 80% rename from frontend/src/utils/slugifyFileName.js rename to frontend/src/utils/slugifyFileName.ts index bb5e69484b..19d70f42d3 100644 --- a/frontend/src/utils/slugifyFileName.js +++ b/frontend/src/utils/slugifyFileName.ts @@ -1,6 +1,6 @@ import slug from 'slug'; -export const slugifyFileName = (name, mimetype) => { +export const slugifyFileName = (name: string, mimetype: string) => { // slugify file names in order to avoid problems on the markdown if (name.lastIndexOf('.') === -1) { name = `${name}.${mimetype.split('/')[1]}`; diff --git a/frontend/src/utils/sorting.js b/frontend/src/utils/sorting.js deleted file mode 100644 index 6c36a2b27c..0000000000 --- a/frontend/src/utils/sorting.js +++ /dev/null @@ -1,19 +0,0 @@ -export function compareTaskId(a, b) { - if (a.properties.taskId > b.properties.taskId) return 1; - if (b.properties.taskId > a.properties.taskId) return -1; - return 0; -} - -export function compareLastUpdate(a, b) { - return new Date(b.properties.actionDate) - new Date(a.properties.actionDate); -} - -export function compareHistoryLastUpdate(a, b) { - return new Date(b.actionDate) - new Date(a.actionDate); -} - -export function compareByPropertyDescending(a, b, property) { - if (a[property] > b[property]) return -1; - if (b[property] > a[property]) return 1; - return 0; -} diff --git a/frontend/src/utils/sorting.ts b/frontend/src/utils/sorting.ts new file mode 100644 index 0000000000..0e56ac5f79 --- /dev/null +++ b/frontend/src/utils/sorting.ts @@ -0,0 +1,41 @@ +import { differenceInDays } from "date-fns"; + +export function compareTaskId(a: { + properties: { + taskId: number; + } +}, b: { + properties: { + taskId: number; + } +}) { + if (a.properties.taskId > b.properties.taskId) return 1; + if (b.properties.taskId > a.properties.taskId) return -1; + return 0; +} + +export function compareLastUpdate(a: { + properties: { + actionDate: string | number | Date; + } +}, b: { + properties: { + actionDate: string | number | Date; + } +}) { + return differenceInDays(new Date(a.properties.actionDate), new Date(b.properties.actionDate)) +} + +export function compareHistoryLastUpdate(a: { + actionDate: string | number | Date; +}, b: { + actionDate: string | number | Date; +}) { + return differenceInDays(new Date(b.actionDate), new Date(a.actionDate)); +} + +export function compareByPropertyDescending(a: any[], b: any[], property: any) { + if (a[property] > b[property]) return -1; + if (b[property] > a[property]) return 1; + return 0; +} diff --git a/frontend/src/utils/testWithIntl.js b/frontend/src/utils/testWithIntl.tsx similarity index 53% rename from frontend/src/utils/testWithIntl.js rename to frontend/src/utils/testWithIntl.tsx index 093c44a1db..78e79f6dfa 100644 --- a/frontend/src/utils/testWithIntl.js +++ b/frontend/src/utils/testWithIntl.tsx @@ -7,39 +7,51 @@ import { QueryClientProvider, QueryClient } from '@tanstack/react-query'; import { store } from '../store'; import userEvent from '@testing-library/user-event'; +import { Store } from 'redux'; -export const createComponentWithIntl = (children, props = { locale: 'en' }) => { - return TestRenderer.create({children}); +export const createComponentWithIntl = (props: { + locale?: string, + children: React.ReactNode, +}) => { + return TestRenderer.create({props.children}); }; -export const createComponentWithReduxAndIntl = (children, props = { locale: 'en' }) => { - return TestRenderer.create({children}); +export const createComponentWithReduxAndIntl = (props: { + locale?: string, + children: React.ReactNode, +}) => { + return TestRenderer.create({props.children}); }; -export const renderWithRouter = (ui, { route = '/' } = {}) => { +export const renderWithRouter = (ui: React.ReactNode, { route = '/' } = {}) => { act(() => window.history.pushState({}, 'Test page', route)); return { - user: userEvent.setup({ copyToClipboard: true }), + user: userEvent.setup({ writeToClipboard: true }), ...render(ui, { wrapper: BrowserRouter }), }; }; -export const ReduxIntlProviders = ({ - children, - props = { locale: 'en' }, - localStore = null, -}: Object) => ( - - {children} +export const ReduxIntlProviders = (props: { + children: React.ReactNode, + locale?: string, + localStore?: Store, +}) => ( + + {props.children} ); -export const IntlProviders = ({ children, props = { locale: 'en' } }: Object) => ( - {children} +export const IntlProviders = (props: { + children: React.ReactNode, + locale?: string, +}) => ( + {props.children} ); -export const QueryClientProviders = ({ children }) => { +export const QueryClientProviders = (props: { + children: React.ReactNode +}) => { const queryClient = new QueryClient({ defaultOptions: { queries: { @@ -50,14 +62,14 @@ export const QueryClientProviders = ({ children }) => { log: console.log, warn: console.warn, // ✅ no more errors on the console for tests - error: process.env.NODE_ENV === 'test' ? () => {} : console.error, + error: import.meta.env.NODE_ENV === 'test' ? () => { } : console.error, }, }); - return {children}; + return {props.children}; }; export const createComponentWithMemoryRouter = ( - component, + component: React.ReactNode, { route = '/starting/path', entryRoute = route } = {}, ) => { const user = userEvent.setup(); diff --git a/frontend/src/utils/tests/snippets/AOI.js b/frontend/src/utils/tests/snippets/AOI.ts similarity index 100% rename from frontend/src/utils/tests/snippets/AOI.js rename to frontend/src/utils/tests/snippets/AOI.ts diff --git a/frontend/src/utils/tests/snippets/feature.js b/frontend/src/utils/tests/snippets/feature.ts similarity index 100% rename from frontend/src/utils/tests/snippets/feature.js rename to frontend/src/utils/tests/snippets/feature.ts diff --git a/frontend/src/utils/tests/snippets/parsedGeometry.js b/frontend/src/utils/tests/snippets/parsedGeometry.ts similarity index 100% rename from frontend/src/utils/tests/snippets/parsedGeometry.js rename to frontend/src/utils/tests/snippets/parsedGeometry.ts diff --git a/frontend/src/utils/tests/snippets/projectMetadata.js b/frontend/src/utils/tests/snippets/projectMetadata.ts similarity index 100% rename from frontend/src/utils/tests/snippets/projectMetadata.js rename to frontend/src/utils/tests/snippets/projectMetadata.ts diff --git a/frontend/src/utils/tests/snippets/taskGrid.js b/frontend/src/utils/tests/snippets/taskGrid.ts similarity index 100% rename from frontend/src/utils/tests/snippets/taskGrid.js rename to frontend/src/utils/tests/snippets/taskGrid.ts diff --git a/frontend/src/utils/tests/snippets/tasksGeometry.js b/frontend/src/utils/tests/snippets/tasksGeometry.ts similarity index 100% rename from frontend/src/utils/tests/snippets/tasksGeometry.js rename to frontend/src/utils/tests/snippets/tasksGeometry.ts diff --git a/frontend/src/views/authorized.js b/frontend/src/views/authorized.tsx similarity index 100% rename from frontend/src/views/authorized.js rename to frontend/src/views/authorized.tsx diff --git a/frontend/src/views/fallback.js b/frontend/src/views/fallback.tsx similarity index 100% rename from frontend/src/views/fallback.js rename to frontend/src/views/fallback.tsx diff --git a/frontend/src/views/home.js b/frontend/src/views/home.jsx similarity index 100% rename from frontend/src/views/home.js rename to frontend/src/views/home.jsx diff --git a/frontend/src/views/management.js b/frontend/src/views/management.jsx similarity index 100% rename from frontend/src/views/management.js rename to frontend/src/views/management.jsx diff --git a/frontend/src/views/messages.js b/frontend/src/views/messages.ts similarity index 100% rename from frontend/src/views/messages.js rename to frontend/src/views/messages.ts diff --git a/frontend/src/views/notFound.js b/frontend/src/views/notFound.jsx similarity index 100% rename from frontend/src/views/notFound.js rename to frontend/src/views/notFound.jsx diff --git a/frontend/src/views/notifications.js b/frontend/src/views/notifications.jsx similarity index 100% rename from frontend/src/views/notifications.js rename to frontend/src/views/notifications.jsx diff --git a/frontend/src/views/projectStats.js b/frontend/src/views/projectStats.js index 819ebd740e..2a6041b257 100644 --- a/frontend/src/views/projectStats.js +++ b/frontend/src/views/projectStats.js @@ -28,7 +28,7 @@ export function ProjectStats() { const { id } = useParams(); useSetTitleTag(`Project #${id} Stats`); const { data: project, status: projectStatus } = useProjectSummaryQuery(id, { - useErrorBoundary: true, + throwOnError: true, }); const { data: tasks, status: tasksStatus } = useTasksQuery(id); const tasksByStatus = useTasksByStatus(tasks); diff --git a/frontend/src/views/root.js b/frontend/src/views/root.jsx similarity index 100% rename from frontend/src/views/root.js rename to frontend/src/views/root.jsx diff --git a/frontend/src/views/taskAction.js b/frontend/src/views/taskAction.js index 61f9bad259..c4aa5f4e7b 100644 --- a/frontend/src/views/taskAction.js +++ b/frontend/src/views/taskAction.js @@ -108,9 +108,9 @@ export function TaskAction({ projectId, action }: Object) { export function TaskActionPossible({ projectId, lockedTasks, action, editor, getTasks }) { const { data: project, status: projectStatus } = useProjectSummaryQuery(projectId, { - useErrorBoundary: true, + throwOnError: true, }); - const { data: tasks, status: tasksStatus } = useTasksQuery(projectId, { useErrorBoundary: true }); + const { data: tasks, status: tasksStatus } = useTasksQuery(projectId, { throwOnError: true }); return (
diff --git a/frontend/src/views/taskSelection.js b/frontend/src/views/taskSelection.js index 2b8cfe7f9b..59b55e1e47 100644 --- a/frontend/src/views/taskSelection.js +++ b/frontend/src/views/taskSelection.js @@ -12,7 +12,7 @@ export function SelectTask() { const navigate = useNavigate(); const token = useSelector((state) => state.auth.token); const { data, status, error } = useProjectSummaryQuery(id, { - useErrorBoundary: (error) => error.response.status !== 404, + throwOnError: (error) => error.response.status !== 404, }); useEffect(() => { diff --git a/frontend/src/views/tests/notFound.test.js b/frontend/src/views/tests/notFound.test.js index 20131ca30c..05c643cc89 100644 --- a/frontend/src/views/tests/notFound.test.js +++ b/frontend/src/views/tests/notFound.test.js @@ -2,7 +2,7 @@ import '@testing-library/jest-dom'; import { render, screen } from '@testing-library/react'; import { IntlProviders } from '../../utils/testWithIntl'; import messages from '../messages'; -import { NotFound } from '../notFound'; +import { NotFound } from '../notFound.jsx'; describe('Not Found', () => { it('should display project not found error', () => { diff --git a/frontend/src/views/welcome.js b/frontend/src/views/welcome.jsx similarity index 100% rename from frontend/src/views/welcome.js rename to frontend/src/views/welcome.jsx diff --git a/frontend/src/vite.d.ts b/frontend/src/vite.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/frontend/src/vite.d.ts @@ -0,0 +1 @@ +/// diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000000..ff4041ee12 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": [ + "ES2020", + "DOM", + "DOM.Iterable" + ], + "module": "ESNext", + "skipLibCheck": true, + "allowJs": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + /* Linting */ + "strict": false, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true + }, + "include": [ + "src" + ] +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000000..e9687eca3e --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,14 @@ +// vite.config.js +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' + +export default defineConfig({ + plugins: [react()], + esbuild: { + loader: "jsx", + include: /src\/.*\.jsx?$/, + // loader: "tsx", + // include: /src\/.*\.[tj]sx?$/, + exclude: [], + }, +}) diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 3837a4c19c..c49fefd6ad 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1396,6 +1396,121 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -2708,6 +2823,14 @@ resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.2.0.tgz#97f9e48fe736aa5c6f4f32cf73c1f19d005f8550" integrity sha512-lVK/svL2HuQdp7jgvlrLkFsUx50Az9chAhxpiPwBqcS83I2pVWvXp98FOcSCCJCV++l115QmzHhFd+ycw1zLBg== +"@redux-devtools/extension@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@redux-devtools/extension/-/extension-3.3.0.tgz#bc775d289f15604c472112920beac2cf4dbb7907" + integrity sha512-X34S/rC8S/M1BIrkYD1mJ5f8vlH0BDqxXrs96cvxSBo4FhMdbhU+GUGsmNYov1xjSyLMHgo8NYrUG8bNX7525g== + dependencies: + "@babel/runtime" "^7.23.2" + immutable "^4.3.4" + "@remix-run/router@1.16.0": version "1.16.0" resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.16.0.tgz#0e10181e5fec1434eb071a9bc4bdaac843f16dcc" @@ -2750,6 +2873,86 @@ estree-walker "^1.0.1" picomatch "^2.2.2" +"@rollup/rollup-android-arm-eabi@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.0.tgz#d941173f82f9b041c61b0dc1a2a91dcd06e4b31e" + integrity sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA== + +"@rollup/rollup-android-arm64@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.0.tgz#7e7157c8543215245ceffc445134d9e843ba51c0" + integrity sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA== + +"@rollup/rollup-darwin-arm64@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.0.tgz#f0a18a4fc8dc6eb1e94a51fa2adb22876f477947" + integrity sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA== + +"@rollup/rollup-darwin-x64@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.0.tgz#34b7867613e5cc42d2b85ddc0424228cc33b43f0" + integrity sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg== + +"@rollup/rollup-linux-arm-gnueabihf@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.0.tgz#422b19ff9ae02b05d3395183d1d43b38c7c8be0b" + integrity sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA== + +"@rollup/rollup-linux-arm-musleabihf@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.0.tgz#568aa29195ef6fc57ec6ed3f518923764406a8ee" + integrity sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w== + +"@rollup/rollup-linux-arm64-gnu@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.0.tgz#22309c8bcba9a73114f69165c72bc94b2fbec085" + integrity sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w== + +"@rollup/rollup-linux-arm64-musl@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.0.tgz#c93c388af6d33f082894b8a60839d7265b2b9bc5" + integrity sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw== + +"@rollup/rollup-linux-powerpc64le-gnu@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.0.tgz#493c5e19e395cf3c6bd860c7139c8a903dea72b4" + integrity sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg== + +"@rollup/rollup-linux-riscv64-gnu@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.0.tgz#a2eab4346fbe5909165ce99adb935ba30c9fb444" + integrity sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg== + +"@rollup/rollup-linux-s390x-gnu@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.0.tgz#0bc49a79db4345d78d757bb1b05e73a1b42fa5c3" + integrity sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw== + +"@rollup/rollup-linux-x64-gnu@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.0.tgz#4fd36a6a41f3406d8693321b13d4f9b7658dd4b9" + integrity sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg== + +"@rollup/rollup-linux-x64-musl@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.0.tgz#10ebb13bd4469cbad1a5d9b073bd27ec8a886200" + integrity sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ== + +"@rollup/rollup-win32-arm64-msvc@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.0.tgz#2fef1a90f1402258ef915ae5a94cc91a5a1d5bfc" + integrity sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ== + +"@rollup/rollup-win32-ia32-msvc@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.0.tgz#a18ad47a95c5f264defb60acdd8c27569f816fc1" + integrity sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg== + +"@rollup/rollup-win32-x64-msvc@4.21.0": + version "4.21.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.0.tgz#20c09cf44dcb082140cc7f439dd679fe4bba3375" + integrity sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ== + "@rushstack/eslint-patch@^1.1.0": version "1.10.2" resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz#053f1540703faa81dea2966b768ee5581c66aeda" @@ -3044,6 +3247,87 @@ "@svgr/plugin-svgo" "^5.5.0" loader-utils "^2.0.0" +"@swc/core-darwin-arm64@1.7.14": + version "1.7.14" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.14.tgz#a4530ec755ea183802cc9dfe4900ab5f6a327fea" + integrity sha512-V0OUXjOH+hdGxDYG8NkQzy25mKOpcNKFpqtZEzLe5V/CpLJPnpg1+pMz70m14s9ZFda9OxsjlvPbg1FLUwhgIQ== + +"@swc/core-darwin-x64@1.7.14": + version "1.7.14" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.7.14.tgz#2c9c717fd28dd1dde9c21cf58b01f1cda7976b1a" + integrity sha512-9iFvUnxG6FC3An5ogp5jbBfQuUmTTwy8KMB+ZddUoPB3NR1eV+Y9vOh/tfWcenSJbgOKDLgYC5D/b1mHAprsrQ== + +"@swc/core-linux-arm-gnueabihf@1.7.14": + version "1.7.14" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.14.tgz#fed055c9c65347177c8df88720f8a51793a4df06" + integrity sha512-zGJsef9qPivKSH8Vv4F/HiBXBTHZ5Hs3ZjVGo/UIdWPJF8fTL9OVADiRrl34Q7zOZEtGXRwEKLUW1SCQcbDvZA== + +"@swc/core-linux-arm64-gnu@1.7.14": + version "1.7.14" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.14.tgz#ca740c8ea26f041b2dc43ba87facec452052814f" + integrity sha512-AxV3MPsoI7i4B8FXOew3dx3N8y00YoJYvIPfxelw07RegeCEH3aHp2U2DtgbP/NV1ugZMx0TL2Z2DEvocmA51g== + +"@swc/core-linux-arm64-musl@1.7.14": + version "1.7.14" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.14.tgz#fbc6fed24f5ad58b948e5b7abe6cd1f07112bef1" + integrity sha512-JDLdNjUj3zPehd4+DrQD8Ltb3B5lD8D05IwePyDWw+uR/YPc7w/TX1FUVci5h3giJnlMCJRvi1IQYV7K1n7KtQ== + +"@swc/core-linux-x64-gnu@1.7.14": + version "1.7.14" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.14.tgz#509a37833e4fbf89506b9291d9bd131fa2017fca" + integrity sha512-Siy5OvPCLLWmMdx4msnEs8HvEVUEigSn0+3pbLjv78iwzXd0qSBNHUPZyC1xeurVaUbpNDxZTpPRIwpqNE2+Og== + +"@swc/core-linux-x64-musl@1.7.14": + version "1.7.14" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.14.tgz#81156cc6ff814ad4b8fcf6eb6658d3f247db0b57" + integrity sha512-FtEGm9mwtRYQNK43WMtUIadxHs/ja2rnDurB99os0ZoFTGG2IHuht2zD97W0wB8JbqEabT1XwSG9Y5wmN+ciEQ== + +"@swc/core-win32-arm64-msvc@1.7.14": + version "1.7.14" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.14.tgz#c605fa783b5fbe1fff784ace4c4bb074b8d6026d" + integrity sha512-Jp8KDlfq7Ntt2/BXr0y344cYgB1zf0DaLzDZ1ZJR6rYlAzWYSccLYcxHa97VGnsYhhPspMpmCvHid97oe2hl4A== + +"@swc/core-win32-ia32-msvc@1.7.14": + version "1.7.14" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.14.tgz#3e15dc3b662c9fab851a38b3e271c8e2da4ba03a" + integrity sha512-I+cFsXF0OU0J9J4zdWiQKKLURO5dvCujH9Jr8N0cErdy54l9d4gfIxdctfTF+7FyXtWKLTCkp+oby9BQhkFGWA== + +"@swc/core-win32-x64-msvc@1.7.14": + version "1.7.14" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.14.tgz#83958d92e9f07865ec9365212111fbc295660f0d" + integrity sha512-NNrprQCK6d28mG436jVo2TD+vACHseUECacEBGZ9Ef0qfOIWS1XIt2MisQKG0Oea2VvLFl6tF/V4Lnx/H0Sn3Q== + +"@swc/core@^1.5.7": + version "1.7.14" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.7.14.tgz#d10492b5a4168cb1e73cf561a315e8b0f62255ed" + integrity sha512-9aeXeifnyuvc2pcuuhPQgVUwdpGEzZ+9nJu0W8/hNl/aESFsJGR5i9uQJRGu0atoNr01gK092fvmqMmQAPcKow== + dependencies: + "@swc/counter" "^0.1.3" + "@swc/types" "^0.1.12" + optionalDependencies: + "@swc/core-darwin-arm64" "1.7.14" + "@swc/core-darwin-x64" "1.7.14" + "@swc/core-linux-arm-gnueabihf" "1.7.14" + "@swc/core-linux-arm64-gnu" "1.7.14" + "@swc/core-linux-arm64-musl" "1.7.14" + "@swc/core-linux-x64-gnu" "1.7.14" + "@swc/core-linux-x64-musl" "1.7.14" + "@swc/core-win32-arm64-msvc" "1.7.14" + "@swc/core-win32-ia32-msvc" "1.7.14" + "@swc/core-win32-x64-msvc" "1.7.14" + +"@swc/counter@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== + +"@swc/types@^0.1.12": + version "0.1.12" + resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.12.tgz#7f632c06ab4092ce0ebd046ed77ff7557442282f" + integrity sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA== + dependencies: + "@swc/counter" "^0.1.3" + "@szmarczak/http-timer@^4.0.5": version "4.0.6" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" @@ -3056,34 +3340,29 @@ resolved "https://registry.yarnpkg.com/@tanstack/eslint-plugin-query/-/eslint-plugin-query-4.38.0.tgz#a8ffd5b4187ed0b522329a1a950fbc3d467e5167" integrity sha512-KmcrnjTQzONBqxNWSVKyPNi5tLq0URvIiWThE9HIK5qePGtB0VqoHfOsn4nuGJD268xDNDpFQjQiko9mMa5iLQ== -"@tanstack/match-sorter-utils@^8.7.0": - version "8.15.1" - resolved "https://registry.yarnpkg.com/@tanstack/match-sorter-utils/-/match-sorter-utils-8.15.1.tgz#715e028ff43cf79ece10bd5a757047a1016c3bba" - integrity sha512-PnVV3d2poenUM31ZbZi/yXkBu3J7kd5k2u51CGwwNojag451AjTH9N6n41yjXz2fpLeewleyLBmNS6+HcGDlXw== - dependencies: - remove-accents "0.5.0" +"@tanstack/query-core@5.52.0": + version "5.52.0" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.52.0.tgz#44070b2d6eb58c3a5ce2788471d842e932294a87" + integrity sha512-U1DOEgltjUwalN6uWYTewSnA14b+tE7lSylOiASKCAO61ENJeCq9VVD/TXHA6O5u9+6v5+UgGYBSccTKDoyMqw== -"@tanstack/query-core@4.36.1": - version "4.36.1" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.36.1.tgz#79f8c1a539d47c83104210be2388813a7af2e524" - integrity sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA== +"@tanstack/query-devtools@5.51.16": + version "5.51.16" + resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.51.16.tgz#d855d00e7939c1a442c2e8ae3ad1a5bd603d003b" + integrity sha512-ajwuq4WnkNCMj/Hy3KR8d3RtZ6PSKc1dD2vs2T408MdjgKzQ3klVoL6zDgVO7X+5jlb5zfgcO3thh4ojPhfIaw== -"@tanstack/react-query-devtools@^4.29.7": - version "4.36.1" - resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-4.36.1.tgz#7e63601135902a993ca9af73507b125233b1554e" - integrity sha512-WYku83CKP3OevnYSG8Y/QO9g0rT75v1om5IvcWUwiUZJ4LanYGLVCZ8TdFG5jfsq4Ej/lu2wwDAULEUnRIMBSw== +"@tanstack/react-query-devtools@^5.52.0": + version "5.52.1" + resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.52.1.tgz#5c15eef755a76ce45099206e0448cd120b3af9dc" + integrity sha512-6KwSm9vcIIK26osQJtT52Gyccz/DyHPT216B7kt4ihg22G2rtGZ7sCXYQO25XEHyVwVingwHdZ7auj+ydgg4Zg== dependencies: - "@tanstack/match-sorter-utils" "^8.7.0" - superjson "^1.10.0" - use-sync-external-store "^1.2.0" + "@tanstack/query-devtools" "5.51.16" -"@tanstack/react-query@^4.29.7": - version "4.36.1" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.36.1.tgz#acb589fab4085060e2e78013164868c9c785e5d2" - integrity sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw== +"@tanstack/react-query@^5.52.0": + version "5.52.0" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.52.0.tgz#671478798f1873983807cf6f62b140c817b3cc9f" + integrity sha512-T8tLZdPEopSD3A1EBZ/sq7WkI76pKLKKiT82F486K8wf26EPgYCdeiSnJfuayssdQjWwLQMQVl/ROUBNmlWgCQ== dependencies: - "@tanstack/query-core" "4.36.1" - use-sync-external-store "^1.2.0" + "@tanstack/query-core" "5.52.0" "@testing-library/dom@>=7": version "10.1.0" @@ -3390,6 +3669,13 @@ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.16.tgz#b1572967f0b8b60bf3f87fe1d854a5604ea70c82" integrity sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ== +"@types/chart.js@^2.9.41": + version "2.9.41" + resolved "https://registry.yarnpkg.com/@types/chart.js/-/chart.js-2.9.41.tgz#4148cdc87d4f98fad44b2883271cd0fa57f05e0d" + integrity sha512-3dvkDvueckY83UyUXtJMalYoH6faOLkWQoaTlJgB4Djde3oORmNP0Jw85HtzTuXyliUHcdp704s0mZFQKio/KQ== + dependencies: + moment "^2.10.2" + "@types/connect-history-api-fallback@^1.3.5": version "1.5.4" resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz#7de71645a103056b48ac3ce07b3520b819c1d5b3" @@ -3427,6 +3713,13 @@ dependencies: "@types/ms" "*" +"@types/dompurify@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-3.0.5.tgz#02069a2fcb89a163bacf1a788f73cb415dd75cb7" + integrity sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg== + dependencies: + "@types/trusted-types" "*" + "@types/earcut@^2.1.0": version "2.1.4" resolved "https://registry.yarnpkg.com/@types/earcut/-/earcut-2.1.4.tgz#5811d7d333048f5a7573b22ddc84923e69596da6" @@ -3448,7 +3741,7 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@^1.0.5": +"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== @@ -3700,6 +3993,13 @@ dependencies: "@types/react" "*" +"@types/react-test-renderer@^18.3.0": + version "18.3.0" + resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-18.3.0.tgz#839502eae70058a4ae161f63385a8e7929cef4c0" + integrity sha512-HW4MuEYxfDbOHQsVlY/XtOvNHftCVEPhJF2pQXXwcUiUF+Oyb0usgp48HSgpK5rt8m9KZb22yqOeZm+rrVG8gw== + dependencies: + "@types/react" "*" + "@types/react-transition-group@^4.4.0": version "4.4.10" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac" @@ -3775,6 +4075,11 @@ dependencies: "@types/node" "*" +"@types/slug@^5.0.9": + version "5.0.9" + resolved "https://registry.yarnpkg.com/@types/slug/-/slug-5.0.9.tgz#e5b213a9d7797d40d362ba85e2a7bbcd4df4ed40" + integrity sha512-6Yp8BSplP35Esa/wOG1wLNKiqXevpQTEF/RcL/NV6BBQaMmZh4YlDwCgrrFSoUE4xAGvnKd5c+lkQJmPrBAzfQ== + "@types/sockjs@^0.3.33": version "0.3.36" resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.36.tgz#ce322cf07bcc119d4cbf7f88954f3a3bd0f67535" @@ -3801,7 +4106,7 @@ dependencies: "@types/jest" "*" -"@types/trusted-types@^2.0.2": +"@types/trusted-types@*", "@types/trusted-types@^2.0.2": version "2.0.7" resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== @@ -3976,6 +4281,13 @@ resolved "https://registry.yarnpkg.com/@vannizhang/wayback-core/-/wayback-core-1.0.6.tgz#43f6a6d3fc4a017f3483cb07c0f49498c14ef884" integrity sha512-Ee5oaqy2vSUyxid+ZoYY0ZEUrNVWxi0wXwp8eU4jpelEneIt9HWSOOtT8Y5RVEAWgMhQQfWsqJZhh7KZxgduVg== +"@vitejs/plugin-react-swc@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.7.0.tgz#e456c0a6d7f562268e1d231af9ac46b86ef47d88" + integrity sha512-yrknSb3Dci6svCd/qhHqhFPDSw0QtjumcqdKMoNNzmOl5lMXTTiqzjWtG4Qask2HdvvzaNgSunbQGet8/GrKdA== + dependencies: + "@swc/core" "^1.5.7" + "@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": version "1.12.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" @@ -5411,13 +5723,6 @@ cookie@^0.4.2: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== -copy-anything@^3.0.2: - version "3.0.5" - resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-3.0.5.tgz#2d92dce8c498f790fa7ad16b01a1ae5a45b020a0" - integrity sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w== - dependencies: - is-what "^4.1.8" - core-js-bundle@^3.19.0: version "3.37.0" resolved "https://registry.yarnpkg.com/core-js-bundle/-/core-js-bundle-3.37.0.tgz#7d79cd80e4d3f5dd4e5a7f869b2575d9f84c0f2c" @@ -6006,6 +6311,11 @@ date-fns@^2.30.0: dependencies: "@babel/runtime" "^7.21.0" +date-fns@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.6.0.tgz#f20ca4fe94f8b754951b24240676e8618c0206bf" + integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== + debug@2.6.9, debug@^2.6.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -6642,6 +6952,35 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + escalade@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" @@ -7384,7 +7723,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2, fsevents@~2.3.2: +fsevents@^2.3.2, fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -8125,6 +8464,11 @@ immutable@^4.0.0: resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.5.tgz#f8b436e66d59f99760dc577f5c99a4fd2a5cc5a0" integrity sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw== +immutable@^4.3.4: + version "4.3.7" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.7.tgz#c70145fc90d89fb02021e65c84eb0226e4e5a381" + integrity sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw== + import-fresh@^3.1.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -8575,11 +8919,6 @@ is-weakset@^2.0.3: call-bind "^1.0.7" get-intrinsic "^1.2.4" -is-what@^4.1.8: - version "4.1.16" - resolved "https://registry.yarnpkg.com/is-what/-/is-what-4.1.16.tgz#1ad860a19da8b4895ad5495da3182ce2acdd7a6f" - integrity sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A== - is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" @@ -9789,10 +10128,10 @@ markdown-table@^3.0.0: resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.3.tgz#e6331d30e493127e031dd385488b5bd326e4a6bd" integrity sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw== -marked@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" - integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== +marked@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/marked/-/marked-14.0.0.tgz#79a1477358a59e0660276f8fec76de2c33f35d83" + integrity sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ== marked@~12.0.2: version "12.0.2" @@ -10400,6 +10739,11 @@ modern-normalize@^1.1.0: resolved "https://registry.yarnpkg.com/modern-normalize/-/modern-normalize-1.1.0.tgz#da8e80140d9221426bd4f725c6e11283d34f90b7" integrity sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA== +moment@^2.10.2: + version "2.30.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" + integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== + moo-color@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/moo-color/-/moo-color-1.0.3.tgz#d56435f8359c8284d83ac58016df7427febece74" @@ -11061,6 +11405,11 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -11796,6 +12145,15 @@ postcss@^8.3.5, postcss@^8.4.23, postcss@^8.4.33, postcss@^8.4.4: picocolors "^1.0.0" source-map-js "^1.2.0" +postcss@^8.4.41: + version "8.4.41" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681" + integrity sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.1" + source-map-js "^1.2.0" + potpack@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.2.tgz#23b99e64eb74f5741ffe7656b5b5c4ddce8dfc14" @@ -12767,11 +13125,6 @@ remark-rehype@^10.0.0: mdast-util-to-hast "^12.1.0" unified "^10.0.0" -remove-accents@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.5.0.tgz#77991f37ba212afba162e375b627631315bed687" - integrity sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A== - renderkid@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" @@ -12932,6 +13285,31 @@ rollup@^2.43.1: optionalDependencies: fsevents "~2.3.2" +rollup@^4.20.0: + version "4.21.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.21.0.tgz#28db5f5c556a5180361d35009979ccc749560b9d" + integrity sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ== + dependencies: + "@types/estree" "1.0.5" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.21.0" + "@rollup/rollup-android-arm64" "4.21.0" + "@rollup/rollup-darwin-arm64" "4.21.0" + "@rollup/rollup-darwin-x64" "4.21.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.21.0" + "@rollup/rollup-linux-arm-musleabihf" "4.21.0" + "@rollup/rollup-linux-arm64-gnu" "4.21.0" + "@rollup/rollup-linux-arm64-musl" "4.21.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.21.0" + "@rollup/rollup-linux-riscv64-gnu" "4.21.0" + "@rollup/rollup-linux-s390x-gnu" "4.21.0" + "@rollup/rollup-linux-x64-gnu" "4.21.0" + "@rollup/rollup-linux-x64-musl" "4.21.0" + "@rollup/rollup-win32-arm64-msvc" "4.21.0" + "@rollup/rollup-win32-ia32-msvc" "4.21.0" + "@rollup/rollup-win32-x64-msvc" "4.21.0" + fsevents "~2.3.2" + run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -13588,16 +13966,7 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -13697,14 +14066,7 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -13815,13 +14177,6 @@ supercluster@^8.0.1: dependencies: kdbush "^4.0.2" -superjson@^1.10.0: - version "1.13.3" - resolved "https://registry.yarnpkg.com/superjson/-/superjson-1.13.3.tgz#3bd64046f6c0a47062850bb3180ef352a471f930" - integrity sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg== - dependencies: - copy-anything "^3.0.2" - supports-color@^5.3.0, supports-color@^5.4.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -14603,7 +14958,7 @@ use-query-params@^2.2.1: dependencies: serialize-query-params "^2.0.2" -use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0: +use-sync-external-store@^1.0.0: version "1.2.2" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9" integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw== @@ -14712,6 +15067,17 @@ vfile@^5.0.0: unist-util-stringify-position "^3.0.0" vfile-message "^3.0.0" +vite@^5.4.2: + version "5.4.2" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.2.tgz#8acb6ec4bfab823cdfc1cb2d6c53ed311bc4e47e" + integrity sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.41" + rollup "^4.20.0" + optionalDependencies: + fsevents "~2.3.3" + vt-pbf@^3.1.1, vt-pbf@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/vt-pbf/-/vt-pbf-3.1.3.tgz#68fd150756465e2edae1cc5c048e063916dcfaac" @@ -15316,7 +15682,7 @@ workbox-window@6.6.1: "@types/trusted-types" "^2.0.2" workbox-core "6.6.1" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -15334,15 +15700,6 @@ wrap-ansi@^6.0.1: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"