Skip to content
This repository has been archived by the owner on May 23, 2023. It is now read-only.

Commit

Permalink
feat: UI improvements (#2)
Browse files Browse the repository at this point in the history
* feat: Share links carry only the group ids, not the full informations

* chore(style): Tab indentation go brrrrr

* fix(ui): Center footer on mobile

* feat(ui): Added hint about hovers

* feat(ui): Message when no result found

* chore(deps): Upgraded to react-script 5.0.0 and nth-check

* chore(deps): Move react-scripts to devDeps

* feat: Basic share implementation with materialui

* feat: Moved group selector to a basic modal

* feat: Move Group Remover to SpeedDialAction + added backdrop

* feat: New group selector modal (but app currently crashes due to change of group)

* fix: New group model is working

* tmp: Hardcode API url

* fix: Removed unused variable

* Use netlify `_rewrite` proxy (#3)

Use the proxy provided by netflify to avoid CORS issues when calling the API. This will remove the need to use another proxy in front of the app.

* feat: Allow to add global groups

* feat: Go back in group selector modal

* chore: Add husky config for pre-commit hook

* cleaning: Remove compact feature

* feat: Persistent labels and color on speedial actions

* fix: Import with new logic

* chore: Change app icon

* chore: Reorganise and clean code

* feat: better organisation of header bar

* docs: updated netlify link on README.md

* feat: settings moved to their own modal

* feat: app bar for title

* chore: removed unused import

* fix: update phrasing to match new UI design

* feat: keep previous choice in Group Selector
  • Loading branch information
nathanaelhoun authored Apr 14, 2022
1 parent efb233d commit e3e5c50
Show file tree
Hide file tree
Showing 44 changed files with 7,157 additions and 11,120 deletions.
2 changes: 2 additions & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ rules:
caseInsensitive: true
newlines-between: always-and-inside-groups
react/no-unescaped-entities: "off"
no-unreachable:
- warn
5 changes: 5 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm run lint:fix
npm run format:write
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
# ade-ufc-onsevoitquand [![Netlify Status](https://api.netlify.com/api/v1/badges/2fd7a0b6-ea48-4ed6-b807-9c0a91749db4/deploy-status)](https://app.netlify.com/sites/admiring-hamilton-f49fca/deploys)
# ade-ufc-onsevoitquand [![Netlify Status](https://api.netlify.com/api/v1/badges/2fd7a0b6-ea48-4ed6-b807-9c0a91749db4/deploy-status)](https://app.netlify.com/sites/ade-ufc-onsevoitquand/deploys)

An easy way to find when you can meet your mates in the University of Franche-Comté.

---

Trouver un créneau pour se voir entre étudiants de l'UFC.

## Development

Run `npm install` then `npm start` to launch the development version, powered by [Create React App](https://create-react-app.dev/)

## Deploy

To avoid CORS issues, the ADE API has to be proxied by the app. Nginx config for reference:
To avoid CORS issues, the ADE API has to be proxied by the app.
The provided `netlify.toml` config includes this functionnality.

If you need it, here is the nginx config for reference:
```nginx
location /api/v1/ {
rewrite ^/api/v1/(.*)$ /jsp/custom/ufc/$1 break;
Expand Down
6 changes: 6 additions & 0 deletions netlify.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

[[redirects]]
from = "/api/v1/*"
to = "https://sedna.univ-fcomte.fr/jsp/custom/ufc/:splat"
status = 200
force = true # COMMENT: ensure that we always redirect
16,081 changes: 5,923 additions & 10,158 deletions package-lock.json

Large diffs are not rendered by default.

19 changes: 16 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@mui/icons-material": "^5.2.5",
"@mui/material": "^5.2.6",
"@mui/styles": "^5.2.3",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
Expand All @@ -12,13 +17,13 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-query": "^3.24.3",
"react-scripts": "4.0.3",
"react-select": "^5.0.0",
"react-tooltip": "^4.2.21",
"sass": "^1.41.1",
"web-vitals": "^1.0.1"
},
"scripts": {
"prepare": "husky install",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
Expand All @@ -29,7 +34,8 @@
"format:write": "prettier --write ."
},
"prettier": {
"printWidth": 100
"printWidth": 100,
"useTabs": true
},
"browserslist": {
"production": [
Expand All @@ -46,6 +52,13 @@
"devDependencies": {
"eslint": "^7.32.0",
"http-proxy-middleware": "^2.0.1",
"prettier": "^2.4.1"
"husky": "^7.0.4",
"prettier": "^2.4.1",
"react-scripts": "5.0.0"
},
"pnpm": {
"overrides": {
"nth-check@<2.0.1": ">=2.0.1"
}
}
}
Binary file modified public/favicon.ico
Binary file not shown.
18 changes: 3 additions & 15 deletions public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/logo192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/logo512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
132 changes: 46 additions & 86 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,98 +1,58 @@
import queryString from "query-string";
import { React, useEffect, useState } from "react";
import ShareIcon from "@mui/icons-material/Share";
import Fab from "@mui/material/Fab";
import { React, useState } from "react";
import { QueryClientProvider } from "react-query";
import ReactTooltip from "react-tooltip";

import "./App.scss";
import DeleteGroups from "./components/GroupeSelector/DeleteGroups";
import GroupSelector from "./components/GroupeSelector/GroupSelector";
import ControlledCheckbox from "./components/miscellaneous/ControlledCheckbox";
import ControlledInput from "./components/miscellaneous/ControlledInput";
import Footer from "./components/miscellaneous/Footer";
import Title from "./components/miscellaneous/Title";
import HeaderBar from "./components/miscellaneous/HeaderBar";
import CompareSchedule from "./components/Schedule/CompareSchedule";
import ShareUrl from "./components/Share/ShareUrl";
import SettingsDialog from "./components/Setttings/SettingsDialog";
import LoadURLConfig from "./components/Share/LoadURLConfig";
import { shareGroupsUrl } from "./components/Share/share";
import queryClient from "./utils/queryClient";
import { useLocalStorage } from "./utils/useLocalStorage";

function App() {
const [config, setConfig] = useLocalStorage("config", { isCompact: true, nbWeeks: 2 });
const [groups, setGroups] = useLocalStorage("saved-groups", {});
const [error, setError] = useState();

useEffect(() => {
console.debug("test");
if (window.location.search !== "") {
let newGroups;
try {
const { groups: JSONGroups } = queryString.parse(window.location.search);
newGroups = JSON.parse(JSONGroups);
localStorage.setItem("saved-groups", JSON.stringify(newGroups));
window.location.search = "";
} catch (error) {
console.error(error, "groups:", newGroups);
setError(
"Impossible de charger les groupes depuis le lien, essaie en copiant-collant directement le lien dans ton navigateur, ou ajoute les groupes manuellement"
);
}
}
}, []);

return (
<QueryClientProvider client={queryClient}>
<header>
<Title />

<div className="buttons">
<GroupSelector
groupId={0}
addGroup={(group) => {
console.info("Adding group", group);
setGroups((oldList) => ({ ...oldList, [group.id]: group.name }));
if (error) {
setError(false);
}
}}
/>
<hr />
<DeleteGroups groups={groups} setGroups={setGroups} />
<hr />
<ShareUrl groups={groups} />

<div id="config">
<ControlledCheckbox
id="config-compact"
value={config.isCompact}
handleInput={(ev) => setConfig((old) => ({ ...old, isCompact: ev.target.checked }))}
data-tip="Cache les heures libres dans tous les emplois du temps en début et en fin de journée"
>
<>Économiser de la place</>
</ControlledCheckbox>
<ControlledInput
id="config-weeks"
value={config.nbWeeks}
handleInput={(ev) =>
setConfig((old) => ({ ...old, nbWeeks: parseInt(ev.target.value) }))
}
data-tip="Nombre de semaines à afficher dans la comparaison"
>
<>Nombre de semaines</>
</ControlledInput>
</div>

{error && <pre className="error">{error}</pre>}
</div>
</header>

<main>
<CompareSchedule groups={groups} config={config} />
</main>

<Footer />

<ReactTooltip multiline effect="solid" />
</QueryClientProvider>
);
const [config, setConfig] = useLocalStorage("config", { nbWeeks: 2 });
const [groups, setGroups] = useLocalStorage("saved-groups-v2", {});

const [isSettingsModalOpened, setIsSettingsModalOpened] = useState(false);

const loadGroups = window.location.search !== "";

if (loadGroups) {
return <LoadURLConfig originalConfig={config} originalGroups={groups} />;
}

return (
<QueryClientProvider client={queryClient}>
<HeaderBar openSettings={() => setIsSettingsModalOpened(true)} />

<main>
<CompareSchedule groups={groups} config={config} />
</main>

<SettingsDialog
open={isSettingsModalOpened}
onClose={() => setIsSettingsModalOpened(false)}
config={config}
groups={groups}
setConfig={setConfig}
setGroups={setGroups}
/>

<Fab
color="primary"
sx={{ position: "fixed", bottom: 16, right: 16 }}
onClick={() => shareGroupsUrl(groups)}
>
<ShareIcon />
</Fab>

<ReactTooltip multiline effect="solid" />
</QueryClientProvider>
);
}

export default App;
Loading

0 comments on commit e3e5c50

Please sign in to comment.