From 21078295fab2d260440877228e3701ef13da1bf2 Mon Sep 17 00:00:00 2001 From: Uriel Ofir Date: Mon, 25 Dec 2023 15:43:20 +0200 Subject: [PATCH 1/3] docs: Add instructions for running the project locally (#337) * README editing: add explanation how to run the project locally. * Instructions in the contribution file. * the update contribution file --- CONTRIBUTION.md | 38 ++++++++++++++++++++++++++++++++------ README.md | 4 ++++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index 54926d11..9a6d7a7e 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -13,13 +13,39 @@ Some of them marked with `help wanted` or `good first issue` - can be good for a Also! you can look at the project and if you find some point that can be improved (it can be unclear documentation as well as UI or backend problem) - you wellcome to add issue to the project issues (which considers a contribution too) -# Starting your environment +# Running the Project Locally + +Follow these steps to run the project on your local machine: + +1. **Fork the Repository:** + Before you clone the repository to your local machine, you need to create a fork of it on GitHub. This allows you to make changes without affecting the original project. To fork the repository, click the "Fork" button at the top right of this page. + +2. **Clone the Repository:** + After forking, you need to clone the repository to your local machine. You can do this by running the following command in your terminal: + + ```bash + git clone https://github.com//open-bus-map-search.git + ``` + Make sure to replace with your actual GitHub username. + +3. **Navigate to the Project Directory:** + Once the repository is cloned, navigate to the project directory by running: + + ```bash + cd open-bus-map-search + ``` +4. **Install Dependencies:** + The project uses Yarn to manage dependencies. If you don't have Yarn installed, you can install it by following the instructions on the [Yarn website](https://classic.yarnpkg.com/en/docs/install). Once Yarn is installed, you can install the project dependencies by running: + ```bash + yarn + ``` +5. **Run the Project:** + After all dependencies are installed, you can start the project by running: + ```bash + yarn start + ``` + The project should now be running on your local machine. Open your web browser and navigate to http://localhost:3000 to view the project. -- Fork the Repository on GitHub (by pressing `fork` button) -- Clone the Repository on your machine (`git clone https://github.com//open-bus-map-search`) -- Define your fork as remote - `git remote set-url origin https://github.com//open-bus-map-search` -- Install dependencies `yarn` -- Run dev server `yarn start` # How to open the PR diff --git a/README.md b/README.md index bb874e91..af6c59ff 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,11 @@ This is the official repository of the open bus (תחב"צ פתוחה / דאטא Please feel free to submit pull requests and contribute to the project. For more details about contributing, see the [CONTRIBUTION.md](CONTRIBUTION.md) file. +# Running the project locally +An explanation how to run the project locally you can [read here](CONTRIBUTION.md#running-the-project-locally). + ## View video (Hebrew language): +### The video will explain you how to contribute to the project: [![video (hebrew) about the project](https://img.youtube.com/vi/6H6jkJCVhgk/0.jpg)](https://www.youtube.com/watch?v=6H6jkJCVhgk) # Easter eggs From ee8a31d3931d5ae9da4124e6f10c7bf20248958c Mon Sep 17 00:00:00 2001 From: Moshe Date: Mon, 25 Dec 2023 15:59:28 +0200 Subject: [PATCH 2/3] feat: add support for dark & light themes (#335) lot of modern websites has darkMode/lightMode toggle Co-authored-by: NoamGaash --- src/layout/ThemeContext.tsx | 52 +++++++++++++++++++ src/layout/header/Header.css | 9 ++++ src/layout/header/Header.tsx | 18 +++++-- src/pages/about/index.tsx | 8 +-- src/routes/MainRoute.tsx | 29 +++-------- src/shared/Widget.tsx | 4 +- tests/clearButton.spec.ts | 97 ++++++++++++++++++++++-------------- tests/realtimemap.spec.ts | 4 +- 8 files changed, 149 insertions(+), 72 deletions(-) create mode 100644 src/layout/ThemeContext.tsx create mode 100644 src/layout/header/Header.css diff --git a/src/layout/ThemeContext.tsx b/src/layout/ThemeContext.tsx new file mode 100644 index 00000000..96d86105 --- /dev/null +++ b/src/layout/ThemeContext.tsx @@ -0,0 +1,52 @@ +// ThemeContext.js +import React, { FC, PropsWithChildren, createContext, useContext, useState } from 'react' +import { ThemeProvider as MuiThemeProvider, createTheme } from '@mui/material/styles' +import { ConfigProvider, theme } from 'antd' +import heIL from 'antd/es/locale/he_IL' +export interface ThemeContextInterface { + toggleTheme: () => void + isDarkTheme: boolean +} +const ThemeContext = createContext({} as ThemeContextInterface) +const darkTheme = createTheme({ + palette: { + mode: 'dark', + }, +}) + +const lightTheme = createTheme({ + palette: { + mode: 'light', + }, +}) + +const { defaultAlgorithm, darkAlgorithm } = theme +export const ThemeProvider: FC = ({ children }) => { + const [isDarkTheme, setIsDarkTheme] = useState(false) + + const toggleTheme = () => { + setIsDarkTheme((prevTheme) => !prevTheme) + } + + const contextValue = { + isDarkTheme, + toggleTheme, + } + + return ( + + + {children} + + + ) +} + +export const useTheme = () => { + return useContext(ThemeContext) +} diff --git a/src/layout/header/Header.css b/src/layout/header/Header.css new file mode 100644 index 00000000..772c03bc --- /dev/null +++ b/src/layout/header/Header.css @@ -0,0 +1,9 @@ +.main-header { + display: flex; + justify-content: flex-end; + align-items: center; + background: #fff; +} +.main-header.dark { + background: #141414; +} diff --git a/src/layout/header/Header.tsx b/src/layout/header/Header.tsx index ef46195e..46abff97 100644 --- a/src/layout/header/Header.tsx +++ b/src/layout/header/Header.tsx @@ -1,15 +1,25 @@ import { Layout } from 'antd' import { MenuOutlined } from '@ant-design/icons' import { useContext } from 'react' -import { LayoutContextInterface, LayoutCtx } from 'src/layout/LayoutContext' - +import { LayoutContextInterface, LayoutCtx } from '../LayoutContext' +import { useTheme } from '../ThemeContext' +import { BulbFilled, BulbOutlined } from '@ant-design/icons' +import './Header.css' +import cn from 'classnames' const { Header } = Layout const MainHeader = () => { const { setDrawerOpen } = useContext(LayoutCtx) + const { isDarkTheme, toggleTheme } = useTheme() return ( -
- setDrawerOpen(true)} /> +
+ setDrawerOpen(true)} className="hideOnDesktop" /> +
 
+
) } diff --git a/src/pages/about/index.tsx b/src/pages/about/index.tsx index 76d43097..f053c0d8 100644 --- a/src/pages/about/index.tsx +++ b/src/pages/about/index.tsx @@ -2,22 +2,22 @@ import styled from 'styled-components' import SlackIcon from '../../resources/slack-icon.svg' import { useTranslation } from 'react-i18next' import Widget from 'src/shared/Widget' -import { Typography } from 'antd' +import { Space, Typography } from 'antd' import './About.scss' const { Title } = Typography const About = () => { return ( -
- קצת עלינו + + קצת עלינו -
+
) } diff --git a/src/routes/MainRoute.tsx b/src/routes/MainRoute.tsx index 4ce2ac0b..9acd17bb 100644 --- a/src/routes/MainRoute.tsx +++ b/src/routes/MainRoute.tsx @@ -1,7 +1,5 @@ import { useCallback, useEffect } from 'react' -import { ConfigProvider } from 'antd' import 'leaflet/dist/leaflet.css' -import heIL from 'antd/es/locale/he_IL' import { useSearchParams } from 'react-router-dom' import { PageSearchState, SearchContext } from '../model/pageState' import moment from 'moment' @@ -12,25 +10,12 @@ import { CacheProvider } from '@emotion/react' import createCache from '@emotion/cache' import rtlPlugin from 'stylis-plugin-rtl' import 'moment/locale/he' -import { heIL as heILmui } from '@mui/x-date-pickers/locales' -import { ThemeProvider, createTheme } from '@mui/material' import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment' import { LocalizationProvider } from '@mui/x-date-pickers' +import { ThemeProvider } from '../layout/ThemeContext' import { PAGES } from '../routes' import { MainLayout } from '../layout' -const theme = createTheme( - { - direction: 'rtl', - palette: { - primary: { - main: '#5f5bff', - }, - }, - }, - heILmui, -) - // Create rtl cache const cacheRtl = createCache({ key: 'muirtl', @@ -85,13 +70,11 @@ export const MainRoute = () => { return ( - - - - - - - + + + + + ) diff --git a/src/shared/Widget.tsx b/src/shared/Widget.tsx index e319c227..520632c6 100644 --- a/src/shared/Widget.tsx +++ b/src/shared/Widget.tsx @@ -1,5 +1,7 @@ +import { Card } from 'antd' + const Widget = (props: { children: React.ReactNode }) => { - return
{props.children}
+ return {props.children} } export default Widget diff --git a/tests/clearButton.spec.ts b/tests/clearButton.spec.ts index 89baa034..b906387d 100644 --- a/tests/clearButton.spec.ts +++ b/tests/clearButton.spec.ts @@ -9,18 +9,6 @@ async function visitPage(page: Page, pageName: string, url: RegExp) { await page.getByRole('progressbar').waitFor({ state: 'hidden' }) } -async function fillDate(page: Page, twoDateElements: boolean = false) { - if (twoDateElements) { - await page.getByLabel('בחירת תאריך').nth(0).click() - await page.getByRole('gridcell', { name: '1', exact: true }).first().click() - await page.getByLabel('בחירת תאריך').nth(1).click() - } else { - await page.getByLabel('בחירת תאריך').nth(1).waitFor({ state: 'detached' }) - await page.getByLabel('בחירת תאריך').click() - } - await page.getByRole('gridcell', { name: '1', exact: true }).first().click() -} - async function selectLineNumberAndRoute(page: Page, lineNumber: Locator, route: Locator) { await lineNumber.fill('64') await route.click() @@ -31,34 +19,44 @@ async function selectLineNumberAndRoute(page: Page, lineNumber: Locator, route: .click() } -test.describe('test clearButton ', () => { - test('test in TimeLinePage', async ({ page }) => { +test.describe('clearButton functionality at TimeLinePage', () => { + test('after clear `line-number` value - should hide `stop` & `route` inputs', async ({ + page, + }) => { await visitPage(page, 'לוח זמנים היסטורי', /timeline/) - await fillDate(page) + await page.getByLabel('תאריך').fill(new Date().toLocaleDateString('en-GB')) const { operator, lineNumber, route, stop } = new Selectors(page) - //clear LineNumber value test await operator.click() await page.getByRole('option', { name: 'אלקטרה אפיקים' }).click() + await selectLineNumberAndRoute(page, lineNumber, route) await lineNumber.click() await page.getByLabel('close').locator('svg').click() await expect(route).not.toBeVisible() await expect(stop).not.toBeVisible() + }) + test('after clear `route` input value - should hide `stop` input', async ({ page }) => { + await visitPage(page, 'לוח זמנים היסטורי', /timeline/) + const { operator, lineNumber, route, stop } = new Selectors(page) + await page.getByLabel('תאריך').fill(new Date().toLocaleDateString('en-GB')) - //clear Operator value test - await selectLineNumberAndRoute(page, lineNumber, route) await operator.click() + await page.getByRole('option', { name: 'אלקטרה אפיקים' }).click() + await selectLineNumberAndRoute(page, lineNumber, route) await page.getByRole('button', { name: 'Clear' }).click() - await expect(route).not.toBeVisible() + await expect(stop).not.toBeVisible() }) - test('test in GapsPage', async ({ page }) => { +}) +test.describe('clearButton functionality at GapsPage', () => { + test('after clear LineNumber input value - stop and route inputs should be hidden', async ({ + page, + }) => { await visitPage(page, 'נסיעות שלא יצאו', /gaps/) - await fillDate(page) + await page.getByLabel('תאריך').fill(new Date().toLocaleDateString('en-GB')) const { operator, lineNumber, route, stop } = new Selectors(page) - //clear LineNumber value test await operator.click() await page.getByRole('option', { name: 'אלקטרה אפיקים' }).click() await selectLineNumberAndRoute(page, lineNumber, route) @@ -68,20 +66,29 @@ test.describe('test clearButton ', () => { await page.getByLabel('close').locator('svg').click() await expect(route).not.toBeVisible() await expect(stop).not.toBeVisible() + }) + test('after clear route input value - stop input should be hidden', async ({ page }) => { + await visitPage(page, 'נסיעות שלא יצאו', /gaps/) + const { operator, lineNumber, route, stop } = new Selectors(page) + await page.getByLabel('תאריך').fill(new Date().toLocaleDateString('en-GB')) - //clear Operator value test - await selectLineNumberAndRoute(page, lineNumber, route) await operator.click() + await page.getByRole('option', { name: 'אלקטרה אפיקים' }).click() + await selectLineNumberAndRoute(page, lineNumber, route) await page.getByRole('button', { name: 'Clear' }).click() - await expect(route).not.toBeVisible() + await expect(stop).not.toBeVisible() }) - test('test in GapsPatternsPage', async ({ page }) => { +}) +test.describe('clear button functionality at GapsPatternsPage', () => { + test('after clear LineNumber input value - stop and route inputs should be hidden', async ({ + page, + }) => { await visitPage(page, 'דפוסי נסיעות שלא יצאו', /gaps_patterns/) - await fillDate(page, true) + await page.getByLabel('התחלה').fill(new Date().toLocaleDateString('en-GB')) + await page.getByLabel('סיום').fill(new Date().toLocaleDateString('en-GB')) const { operator, lineNumber, route, stop } = new Selectors(page) - //clear LineNumber value test await operator.click() await page.getByRole('option', { name: 'אלקטרה אפיקים' }).click() await selectLineNumberAndRoute(page, lineNumber, route) @@ -89,17 +96,26 @@ test.describe('test clearButton ', () => { await page.getByLabel('close').locator('svg').click() await expect(route).not.toBeVisible() await expect(stop).not.toBeVisible() + }) + test('after clear route input value - stop input should be hidden', async ({ page }) => { + await visitPage(page, 'דפוסי נסיעות שלא יצאו', /gaps_patterns/) + await page.getByLabel('התחלה').fill(new Date().toLocaleDateString('en-GB')) + await page.getByLabel('סיום').fill(new Date().toLocaleDateString('en-GB')) + const { operator, lineNumber, route, stop } = new Selectors(page) - //clear Operator value test - await selectLineNumberAndRoute(page, lineNumber, route) await operator.click() + await page.getByRole('option', { name: 'אלקטרה אפיקים' }).click() + await selectLineNumberAndRoute(page, lineNumber, route) await page.getByRole('button', { name: 'Clear' }).click() - await expect(route).not.toBeVisible() await expect(stop).not.toBeVisible() }) - test('test in SingleLineMapPage', async ({ page }) => { +}) +test.describe('clear button functionality at SingleLineMapPage', () => { + test('after clear LineNumber input value - stop and route inputs should be hidden', async ({ + page, + }) => { await visitPage(page, 'מפה לפי קו', /single-line/) - await fillDate(page) + await page.getByLabel('תאריך').fill(new Date().toLocaleDateString('en-GB')) const { operator, lineNumber, route, stop } = new Selectors(page) //clear LineNumber value test @@ -110,15 +126,22 @@ test.describe('test clearButton ', () => { await page.getByLabel('close').locator('svg').click() await expect(route).not.toBeVisible() await expect(stop).not.toBeVisible() + }) + test('after clear route input value - stop input should be hidden', async ({ page }) => { + await visitPage(page, 'מפה לפי קו', /single-line/) + const { operator, lineNumber, route, stop } = new Selectors(page) + await page.getByLabel('תאריך').fill(new Date().toLocaleDateString('en-GB')) - //clear Operator value test - await selectLineNumberAndRoute(page, lineNumber, route) await operator.click() + await page.getByRole('option', { name: 'אלקטרה אפיקים' }).click() + await selectLineNumberAndRoute(page, lineNumber, route) await page.getByRole('button', { name: 'Clear' }).click() - await expect(route).not.toBeVisible() + await expect(stop).not.toBeVisible() }) - test('test in RealtimeMapPage', async ({ page }) => { +}) +test.describe('clear button functionality at RealtimeMapPage', () => { + test('after clear the `minutes` input - it should has value equals to `1`', async ({ page }) => { await visitPage(page, 'מפה בזמן אמת', /map/) const minutes = page.getByLabel('דקות') let getValueAttribute = await minutes.getAttribute('value') diff --git a/tests/realtimemap.spec.ts b/tests/realtimemap.spec.ts index 5171b852..f4f55300 100644 --- a/tests/realtimemap.spec.ts +++ b/tests/realtimemap.spec.ts @@ -5,8 +5,6 @@ test('realtime-map page', async ({ page }) => { await page.getByText('מפה בזמן אמת', { exact: true }).click() await page.waitForURL(/map/) await page.getByRole('progressbar').waitFor({ state: 'hidden' }) - await page.getByLabel('בחירת תאריך').nth(1).waitFor({ state: 'detached' }) - await page.getByLabel('בחירת תאריך').click() - await page.getByRole('gridcell', { name: '1', exact: true }).click() + await page.getByLabel('תאריך').fill(new Date().toLocaleDateString('en-GB')) await page.getByLabel('דקות').fill('6') }) From 90b650e3be97da3b1913c93af0edf95e0d377c2e Mon Sep 17 00:00:00 2001 From: Or Malka <107395990+xoRmalka@users.noreply.github.com> Date: Tue, 26 Dec 2023 09:44:32 +0200 Subject: [PATCH 3/3] fix: useCallback for GitHub link onClick (#344) --- src/layout/sidebar/GitHubLink/GitHubLink.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/layout/sidebar/GitHubLink/GitHubLink.tsx b/src/layout/sidebar/GitHubLink/GitHubLink.tsx index 30a907d6..431d7dc7 100644 --- a/src/layout/sidebar/GitHubLink/GitHubLink.tsx +++ b/src/layout/sidebar/GitHubLink/GitHubLink.tsx @@ -1,5 +1,6 @@ import { GithubOutlined } from '@ant-design/icons' import { useTranslation } from 'react-i18next' +import { useCallback } from 'react' import './GitHubLink.scss' export default function GitHubLink() { @@ -12,9 +13,9 @@ export default function GitHubLink() { element: null, } - const handleClick = () => { + const handleClick = useCallback(() => { window.open(data.path, '_blank') - } + }, []) return (