diff --git a/README.md b/README.md index b685aa0..9731adf 100644 --- a/README.md +++ b/README.md @@ -99,22 +99,22 @@ npm run dev:android:device ## Environment variables -There are some environment variables that you can set to customize the app during development. The project uses vite's +There are some environment variables that you can set to customize the app during development. The project uses vite's environment variables management. The variables are intended for use in development only and should not be used in -production. You can copy the `.env.development` file to a `.env.development.local` file that will be automatically ignored by +production. You can copy the `.env.development` file to a `.env.development.local` file that will be automatically +ignored by git and set your custom variables there following the same format. The variables can then be accessed in the code using -`import.meta.env.VITE_VARIABLE_NAME`. For more information, you can refer to the [vite documentation](https://vitejs.dev/guide/env-and-mode). +`import.meta.env.VITE_VARIABLE_NAME`. For more information, you can refer to +the [vite documentation](https://vitejs.dev/guide/env-and-mode). | Variable | Type | Default | Description | |--------------------------------|-----------|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `VITE_SKIP_ONBOARDING` | `boolean` | `false` | Skips the onboarding process and goes directly to the login screen. This requires `VITE_SKYPORTAL_TOKEN`, `VITE_SKY | +| `VITE_SKIP_ONBOARDING` | `boolean` | `false` | Skips the onboarding process and goes directly to the login screen. This requires `VITE_SKYPORTAL_TOKEN`, `VITE_SKYPORTAL_INSTANCE_URL`, and `VITE_SKYPORTAL_INSTANCE_NAME` to be defined | | `VITE_SKYPORTAL_TOKEN` | `string` | `undefined` | The token to use to authenticate with the SkyPortal backend. This is required if `VITE_SKIP_ONBOARDING` is set to `true`. | | `VITE_SKYPORTAL_INSTANCE_URL` | `string` | `undefined` | The URL of the SkyPortal instance to connect to. This is required if `VITE_SKIP_ONBOARDING` is set to `true`. | | `VITE_SKYPORTAL_INSTANCE_NAME` | `string` | `undefined` | The name of the SkyPortal instance to connect to. This is required if `VITE_SKIP_ONBOARDING` is set to `true`. | | `VITE_CLEAR_AUTH` | `boolean` | `false` | Clears the authentication token and instance URL from the local storage. This is useful when you want to reset the app to the onboarding state each time you start the development server. | - - ## Directory structure ### `src/` @@ -135,4 +135,275 @@ This directory contains mock data that is used to develop and test the app witho ### `doc/` -This directory contains documentation and images related to the project. \ No newline at end of file +This directory contains documentation and images related to the project. + +## Development guidelines + +### Components + +The React components are all located inside modules, in a `components` directory. If a component is being used in +multiple modules, it should be in +the `common/` directory. +The only naming convention for the components of this repository is to use Pascal-case. To create a new +component, one should first create a directory with the name and the component and put the actual component file inside +of this directory. They can also add a sass style file with the same name as the component in this directory like so: + +```bash +|- myModule + |- components + |- NewComponent + |- NewComponent.jsx + |- NewComponent.scss +``` + +The components themselves are arrow function components with named exports. + +```jsx +export const NewComponent = ({ paramA, paramB }) => { + // Your component code here... +} +``` + +#### Styling + +This project uses Sass for styling components. Although you should strive to use Ionic components as most as you can. As +they come with built-in styles that will integrate smoothly with the rest of the UI. You should try to write as little +styling code as you can and rely more on Ionic components. If you do need some custom styles, a good practice is to +always give a style class to your component's top-level element. For example in the CandidateScanner component: + +```jsx +return ( +
+ {/* ... */} +
+); +``` + +And then in CandidateScanner.scss, we have: + +```scss +.candidate-scanner { + display: grid; + grid-template-columns: 1fr; + grid-template-rows: 90% 10%; + height: 100%; + + .embla { + // ... + } + + .action-buttons-container { + // ... + } +} +``` + +Do not forget to import the style file in your React component by adding: + +```jsx +import "./CandidateScanner.scss"; +``` + +If you need to define global styles, you can put them in the `global.scss` file. + +#### Theming + +In addition to the styles built into its components, Ionic also provides css variables that you can use in your own +custom styles like `--ion-color-primary` or `--ion-safe-area-top`. You can find more about this on +the [Ionic website](https://www.figma.com/community/plugin/1034969338659738588/material-theme-builder). Ionic also +allows overriding some of these variables +values by providing your own. This is how the color theme for this application has been defined. You can find all the +theme colors in the `theme/variables.scss` file. You should only use theme colors in your components as they will also +automatically adapt to dark theme. The theme colors in this project have been generated using +the [Material Theme Builder](https://www.figma.com/community/plugin/1034969338659738588/material-theme-builder) Figma +plugin. So they respect accessibility standards and also just work well together. + +#### Screen components + +In any React application you have some components that make up entire screens by composing other components. These +screen components are then used in the routing of the application as destinations. With Ionic, a screen component needs +to be wrapped into an ``. This will ensure the component will have the expected behavior when the user +navigates to it. The basic layout of an `` is as follows: + +```jsx + + + {/* ... */} + + + {/* ... */} + + +``` + +The `` can contain an `` with an `` like this: + +```jsx + + + Title + + +``` + +And the `` contains the body of your page. + +The screen components are to be put in a `screens` directory inside a module and the naming convention is to suffix them +with `Screen`. + +#### Skeleton components + +Ionic provides an easy way to create skeletons. This offers a better experience than a basic loader as users can have an +idea +of what is gonna be displayed. A good practice is that, if you have a loading delay and you already know what is going +to be displayed after it, +you can create a skeleton for this content instead of displaying a loader. You can use the same styling file as the real +component for this and +if you do, you should include the skeleton file in the same directory as your component: + +```bash +|- myModule + | - components + |- NewComponent + |- NewComponent.jsx + |- NewComponent.scss + |- NewComponentSkeleton.jsx +``` + +### Modules + +Modules help keeping the code base organized and enhance scalability. The contain components and code that are related +together. The naming convention for modules is to use camel-case. Module names should be short and descriptive. They +usually +refer to a specific part of the application or a group of related functionalities. A module in this repository +has the following structure: + +```bash +|- myModule + |- components + |- Component1 + |- Component2 + |- Component3 + |- screens + |- Screen1 + |- Screen2 + |- myModult.lib.js + |- myModule.hooks.js + |- myModule.requests.js +``` + +Other than the component directories, there are three files that can be added to the module. + +- `myModule.lib.js` contains all the business logic of the module. Here you can put functions, constants and types that + are being used by the components of this module. +- `myModule.hooks.js` contains all the hooks being used in this module. Every TanStack queries should be defined + there + as well as other needed hooks. +- `myModule.requests.js` contains all the network requests of this module. +- `components/` contains the components + +Normally, the dependencies between these 3 files should be in this order `myModult.lib.js` -> +`myModule.hooks.js` -> +`myModule.requests.js`. If you end up with a different order of dependencies make sure that all of your hooks are +in +the `myModule.hooks.js` and that all the logic is in `myModule.lib.js`. + +### State + +There is no state management library in this repository. The app only relies on TanStack Query to get the state from the +SkyPortal instance backend. This allows for less code to write and requires that every piece of data needed by a +component be made available through a TanStack query. + +#### Example + +Some components in the module need access to the user's accessible groups. A request `fetchGroups` has been created in +the `common.requests.js` file: + +```js +export async function fetchGroups(userInfo) { + let response = await CapacitorHttp.get({ + url: `${userInfo.instance.url}/api/groups`, + headers: { + Authorization: `token ${userInfo.token}`, + }, + }); + return response.data.data; +} +``` + +Then in the `common.hooks.js` file we have defined a `useUserAccessibleGroups` hook: + +```js +export const useUserAccessibleGroups = () => { + const { + status, + error, + } = useQuery({ + queryKey: [QUERY_KEYS.GROUPS], + queryFn: () => fetchGroups(), + }); + return { + userAccessibleGroups: groups?.user_accessible_groups, + status, + error, + }; +}; +``` + +It uses a key defined on the `QUERY_KEYS` constant. This is very important, you should always use this `QUERY_KEYS` in +the `queryKey` field of your request as it will help you keep track of them and each of your keys should be unique. +Failing to do so will produce unexpected results with TanStack Query. +Finally, we can use our new hook in a component. For example in the `RecentProfiles` component: + +```js +export const RecentProfiles = () => { + // ... + const { userAccessibleGroups } = useUserAccessibleGroups(); + + return ( +
+ {/* ... */} +
+ {profiles && userAccessibleGroups && (<>{/* ... */})} + {(!profiles || !userAccessibleGroups) && } +
+ {/* ... */} +
+ ); +}; +``` + +The data from a TanStack query is undefined until the query completes so you have to check its value before using it. + +This approach eliminates the need for a state management library. TanStack Query also caches the data it fetches and +automatically invalidates this cache after some time or after an action has been taken. You can read more about TanStack +Query on its [official website](https://tanstack.com/query/latest/docs/framework/react/overview). + +The only exception to this pattern in the application is the `userInfo`. `userInfo` stores the token and instance of the +user. The user provides them when they log in, and it is then stored in the application's preferences for the next app +launches. At every app launch, the `userInfo` is fetched from the preferences and propagated through the whole +application using the React Context API. As you can see in App.jsx: + +```jsx +const { data } = useAppStart(); +return ( + + + {/* ... */} + + +); +``` + +### Typings + +The project does not use TypeScript which is the default for Ionic React applications. Instead, it uses JavaScript, just +like in the web version and it relies on jsdoc when types are needed. The jsdoc types are located close to the code that +uses them. You can check types in the whole repository by running `tsc --noEmit`. \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index 819c6f4..1852f0f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -35,40 +35,41 @@ import "@ionic/react/css/display.css"; import "@ionic/react/css/palettes/dark.class.css"; // import "@ionic/react/css/palettes/dark.system.css"; /* Theme variables */ +import "./global.scss"; import "./theme/variables.scss"; import { IonReactRouter } from "@ionic/react-router"; import { Redirect, Route } from "react-router"; -import OnboardingScreen from "./onboarding/OnboardingScreen/OnboardingScreen.jsx"; +import OnboardingScreen from "./onboarding/screens/OnboardingScreen/OnboardingScreen.jsx"; import React, { useEffect, useState } from "react"; -import CheckQRCodeScreen from "./onboarding/CheckQRCodeScreen/CheckQRCodeScreen.jsx"; -import { LoginOkScreen } from "./onboarding/LoginOk/LoginOkScreen.jsx"; -import { useAppStart } from "./common/hooks.js"; -import { ScanningOptionsScreen } from "./scanning/scanningOptions/ScanningOptionsScreen/ScanningOptionsScreen.jsx"; -import { MainScanningScreen } from "./scanning/scanningSession/MainScanningScreen/MainScanningScreen.jsx"; -import { SourceListScreen } from "./sources/SourceListScreen/SourceListScreen.jsx"; +import CheckQRCodeScreen from "./onboarding/screens/CheckQRCodeScreen/CheckQRCodeScreen.jsx"; +import { LoginOkScreen } from "./onboarding/screens/LoginOkScreen/LoginOkScreen.jsx"; +import { useAppStart } from "./common/common.hooks.js"; +import { ScanningOptionsScreen } from "./scanning/scanningOptions/screens/ScanningOptionsScreen/ScanningOptionsScreen.jsx"; +import { MainScanningScreen } from "./scanning/scanningSession/screens/MainScanningScreen/MainScanningScreen.jsx"; +import { SourceListTab } from "./sources/screens/SourceListTab/SourceListTab.jsx"; import { compassOutline, listOutline, personCircleOutline, } from "ionicons/icons"; -import { ScanningRecap } from "./scanning/scanningSession/ScanningRecap/ScanningRecap.jsx"; -import { AppContext, UserContext } from "./common/context.js"; -import { ScanningHome } from "./scanning/scanningOptions/ScanningHome/ScanningHome.jsx"; -import { ScanningNewProfileScreen } from "./scanning/scanningOptions/ScanningNewProfileScreen/ScanningNewProfileScreen.jsx"; -import { ScanningProfiles } from "./scanning/scanningOptions/ScanningProfiles/ScanningProfiles.jsx"; -import { UserProfileScreen } from "./userProfile/UserProfileScreen/UserProfileScreen.jsx"; -import { setDarkModeInDocument } from "./common/util.js"; +import { ScanningRecapScreen } from "./scanning/scanningSession/screens/ScanningRecapScreen/ScanningRecapScreen.jsx"; +import { AppContext, UserContext } from "./common/common.context.js"; +import { ScanningHomeTab } from "./scanning/scanningOptions/screens/ScanningHomeTab/ScanningHomeTab.jsx"; +import { ScanningNewProfileScreen } from "./scanning/scanningOptions/screens/ScanningNewProfileScreen/ScanningNewProfileScreen.jsx"; +import { ScanningProfilesScreen } from "./scanning/scanningOptions/screens/ScanningProfilesScreen/ScanningProfilesScreen.jsx"; +import { UserProfileTab } from "./userProfile/screens/UserProfileScreen/UserProfileTab.jsx"; +import { setDarkModeInDocument } from "./common/common.lib.js"; setupIonicReact(); /** * @param {Object} props - * @param {import("./common/util").DarkMode} props.darkMode + * @param {import("./common/common.lib.js").DarkMode} props.darkMode * @returns {React.JSX.Element} */ const App = ({ darkMode: initialDarkMode }) => { const { data } = useAppStart(); - /** @type {[import("./common/util").DarkMode, React.Dispatch]} */ + /** @type {[import("./common/common.lib.js").DarkMode, React.Dispatch]} */ const [darkMode, setDarkMode] = useState(initialDarkMode); const [userInfo, setUserInfo] = useState({ instance: { name: "", url: "" }, @@ -126,7 +127,7 @@ const App = ({ darkMode: initialDarkMode }) => { ) : ( <> - + @@ -138,7 +139,7 @@ const App = ({ darkMode: initialDarkMode }) => { - + @@ -159,13 +160,13 @@ const App = ({ darkMode: initialDarkMode }) => { - + - + - + diff --git a/src/common/context.js b/src/common/common.context.js similarity index 51% rename from src/common/context.js rename to src/common/common.context.js index ba9dffb..18b6c53 100644 --- a/src/common/context.js +++ b/src/common/common.context.js @@ -1,15 +1,15 @@ import { createContext } from "react"; export const UserContext = createContext({ - /** @type {import("../onboarding/auth").UserInfo} */ + /** @type {import("../onboarding/onboarding.lib.js").UserInfo} */ userInfo: { instance: { name: "", url: "" }, token: "" }, - /** @type {React.Dispatch} */ + /** @type {React.Dispatch} */ updateUserInfo: (userInfo) => {}, }); export const AppContext = createContext({ - /** @type {import("./util").DarkMode} */ + /** @type {import("./common.lib.js").DarkMode} */ darkMode: "auto", - /** @type {React.Dispatch} */ + /** @type {React.Dispatch} */ updateDarkMode: (newDarkMode) => {}, }); diff --git a/src/common/hooks.js b/src/common/common.hooks.js similarity index 76% rename from src/common/hooks.js rename to src/common/common.hooks.js index 7ab04c2..fc40e6e 100644 --- a/src/common/hooks.js +++ b/src/common/common.hooks.js @@ -1,17 +1,12 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"; -import { QUERY_KEYS } from "./constants.js"; -import { fetchSources } from "../sources/sources.js"; -import { - clearPreference, - getPreference, - setPreference, -} from "./preferences.js"; +import { fetchSources } from "../sources/sources.lib.js"; import config from "../config.js"; -import { fetchUserProfile } from "../onboarding/auth.js"; -import { fetchConfig } from "./requests.js"; -import { fetchGroups } from "../scanning/scanningRequests.js"; +import { fetchUserProfile } from "../onboarding/onboarding.lib.js"; +import { fetchConfig } from "./common.requests.js"; +import { fetchGroups } from "../scanning/scanning.requests.js"; import { useContext } from "react"; -import { UserContext } from "./context.js"; +import { UserContext } from "./common.context.js"; +import { clearPreference, getPreference, QUERY_KEYS, setPreference } from "./common.lib.js"; /** * @typedef {"success" | "error" | "pending"} QueryStatus @@ -21,13 +16,13 @@ import { UserContext } from "./context.js"; * @param {Object} props * @param {number} props.page * @param {number} props.numPerPage - * @returns {{sources: import("../sources/sources.js").Source[]|undefined, status: QueryStatus, error: any|undefined}} + * @returns {{sources: import("../sources/sources.lib.js").Source[]|undefined, status: QueryStatus, error: any|undefined}} */ export const useFetchSources = ({ page, numPerPage }) => { const { userInfo } = useContext(UserContext); const { - /** @type {import("../sources/sources.js").Source[]} */ data: sources, + /** @type {import("../sources/sources.lib.js").Source[]} */ data: sources, status, error, } = useQuery({ @@ -54,7 +49,7 @@ export const useFetchSources = ({ page, numPerPage }) => { */ /** - * @returns {{data: {userInfo: import("../onboarding/auth.js").UserInfo|null, userProfile: import("../onboarding/auth.js").UserProfile|null}, status: QueryStatus, error: any|undefined}} + * @returns {{data: {userInfo: import("../onboarding/onboarding.lib.js").UserInfo|null, userProfile: import("../onboarding/onboarding.lib.js").UserProfile|null}, status: QueryStatus, error: any|undefined}} */ export const useAppStart = () => { const queryClient = useQueryClient(); @@ -117,12 +112,12 @@ export const useAppStart = () => { }; /** - * @returns {{userAccessibleGroups: import("../scanning/scanningLib.js").Group[]|undefined, status: QueryStatus, error: any|undefined}} + * @returns {{userAccessibleGroups: import("../scanning/scanning.lib.js").Group[]|undefined, status: QueryStatus, error: any|undefined}} */ export const useUserAccessibleGroups = () => { const { userInfo } = useContext(UserContext); const { - /** @type {import("../scanning/scanningLib.js").GroupsResponse} */ data: groups, + /** @type {import("../scanning/scanning.lib.js").GroupsResponse} */ data: groups, status, error, } = useQuery({ @@ -138,7 +133,7 @@ export const useUserAccessibleGroups = () => { /** * - * @returns {{bandpassesColors: import("./requests.js").BandpassesColors|undefined,status: QueryStatus, error: any|undefined}} + * @returns {{bandpassesColors: import("./common.requests.js").BandpassesColors|undefined,status: QueryStatus, error: any|undefined}} */ export const useBandpassesColors = () => { const { userInfo } = useContext(UserContext); @@ -154,7 +149,7 @@ export const useBandpassesColors = () => { }; /** - * @returns {{userProfile: import("../onboarding/auth.js").UserProfile|undefined, status: QueryStatus, error: any|undefined}} + * @returns {{userProfile: import("../onboarding/onboarding.lib.js").UserProfile|undefined, status: QueryStatus, error: any|undefined}} */ export const useUserProfile = () => { const { userInfo } = useContext(UserContext); diff --git a/src/common/common.lib.js b/src/common/common.lib.js new file mode 100644 index 0000000..350d733 --- /dev/null +++ b/src/common/common.lib.js @@ -0,0 +1,138 @@ +import { Preferences } from "@capacitor/preferences"; + +/** + * + * @typedef {Object} SkyPortalInstance + * @property {string} name - The name of the instance + * @property {string} url - The URL of the instance + */ + +/** + * @typedef {"all" | "savedToAllSelected" | "savedToAnySelected" | "savedToAnyAccessible" | "notSavedToAnyAccessible" | "notSavedToAnySelected" | "notSavedToAllSelected"} SavedStatus + */ + +/** + * Navigate to a new path with params + * @param {import("history").History} history + * @param {string} path + * @param {Object} options + * @param {Record} [options.params] + * @param {any} [options.state] + * @param {boolean} [options.replace] + */ +export const navigateWithParams = ( + history, + path, + { params, state, replace = false }, +) => { + history[replace ? "replace" : "push"]( + `${path}?${new URLSearchParams(params).toString()}`, + state, + ); +}; + +/** + * @typedef {"auto"|"light"|"dark"} DarkMode + */ + +/** + * @param {DarkMode} darkModePreference + * @param {boolean} [systemIsDark] + * @returns {boolean} + */ +export const isActuallyDarkMode = ( + darkModePreference, + systemIsDark = window.matchMedia("(prefers-color-scheme: dark)").matches, +) => { + return ( + darkModePreference === "dark" || + (systemIsDark && darkModePreference === "auto") + ); +}; + +/** + * @param {DarkMode} darkModePreference + * @param {boolean} [systemIsDark] + */ +export const setDarkModeInDocument = ( + darkModePreference, + systemIsDark = window.matchMedia("(prefers-color-scheme: dark)").matches, +) => { + document.documentElement.classList.toggle( + "ion-palette-dark", + isActuallyDarkMode(darkModePreference, systemIsDark), + ); +}; + +/** + * Set a preference in the app + * @param {string} key - The key to associate with the value being set in preferences. + * @param {any} value - The value to set in preferences with the associated key. + * @returns {Promise} + */ +export async function setPreference(key, value) { + return await Preferences.set({ key, value: JSON.stringify(value) }); +} + +/** + * Get a preference in the app + * @param {string} key - The key to retrieve the value from preferences. + * @returns {Promise} + */ +export async function getPreference(key) { + const pref = await Preferences.get({ key }); + if (pref.value !== null) { + return JSON.parse(pref.value); + } + return null; +} + +/** + * Clear a preference in the app + * @param {string} key - The key to clear from preferences. + * @returns {Promise} + */ +export async function clearPreference(key) { + return await Preferences.remove({ key }); +} + +/** + * The instances that are available for login + * @type {SkyPortalInstance[]} + */ +export const INSTANCES = [ + { name: "ICARE", url: "https://skyportal-icare.ijclab.in2p3.fr" }, + { name: "FRITZ", url: "https://fritz.science" }, + { name: "FRITZ preview", url: "https://preview.fritz.science" }, +]; +export const QUERY_PARAMS = { + TOKEN: "token", + INSTANCE: "instance", +}; +export const QUERY_KEYS = { + CANDIDATES: "candidates", + SOURCES: "sources", + USER_PROFILE: "user", + USER_INFO: "userInfo", + GROUPS: "groups", + SOURCE_PHOTOMETRY: "sourcePhotometry", + CONFIG: "config", + APP_START: "appStart", + BANDPASS_COLORS: "bandpassColors", + SCANNING_PROFILES: "scanningProfiles", + ANNOTATIONS_INFO: "annotationsInfo", + APP_PREFERENCES: "appPreferences", +}; +/** + * @type {Object.} + */ +export const SAVED_STATUS = { + ALL: "all", + SAVED_TO_ALL_SELECTED: "savedToAllSelected", + SAVED_TO_ANY_SELECTED: "savedToAnySelected", + SAVED_TO_ANY_ACCESSIBLE: "savedToAnyAccessible", + NOT_SAVED_TO_ANY_ACCESSIBLE: "notSavedToAnyAccessible", + NOT_SAVED_TO_ANY_SELECTED: "notSavedToAnySelected", + NOT_SAVED_TO_ALL_SELECTED: "notSavedToAllSelected", +}; +export const CANDIDATES_PER_PAGE = 50; diff --git a/src/common/requests.js b/src/common/common.requests.js similarity index 87% rename from src/common/requests.js rename to src/common/common.requests.js index 0eda3fa..0cbbfe1 100644 --- a/src/common/requests.js +++ b/src/common/common.requests.js @@ -15,7 +15,7 @@ import { CapacitorHttp } from "@capacitor/core"; /** * Fetch the configuration from the server - * @param {import("../onboarding/auth").UserInfo} userInfo - The user info + * @param {import("../onboarding/onboarding.lib.js").UserInfo} userInfo - The user info * @returns {Promise} */ export const fetchConfig = async (userInfo) => { diff --git a/src/common/ControlledDateTime/ControlledDateTime.jsx b/src/common/components/ControlledDateTime/ControlledDateTime.jsx similarity index 100% rename from src/common/ControlledDateTime/ControlledDateTime.jsx rename to src/common/components/ControlledDateTime/ControlledDateTime.jsx diff --git a/src/common/ControlledInput/ControlledInput.jsx b/src/common/components/ControlledInput/ControlledInput.jsx similarity index 100% rename from src/common/ControlledInput/ControlledInput.jsx rename to src/common/components/ControlledInput/ControlledInput.jsx diff --git a/src/common/ControlledRadioGroup/ControlledRadioGroup.jsx b/src/common/components/ControlledRadioGroup/ControlledRadioGroup.jsx similarity index 100% rename from src/common/ControlledRadioGroup/ControlledRadioGroup.jsx rename to src/common/components/ControlledRadioGroup/ControlledRadioGroup.jsx diff --git a/src/common/ErrorMessage/ErrorMessage.jsx b/src/common/components/ErrorMessage/ErrorMessage.jsx similarity index 100% rename from src/common/ErrorMessage/ErrorMessage.jsx rename to src/common/components/ErrorMessage/ErrorMessage.jsx diff --git a/src/common/ErrorMessage/ErrorMessage.scss b/src/common/components/ErrorMessage/ErrorMessage.scss similarity index 100% rename from src/common/ErrorMessage/ErrorMessage.scss rename to src/common/components/ErrorMessage/ErrorMessage.scss diff --git a/src/common/ErrorMessageContainer/ErrorMessageContainer.jsx b/src/common/components/ErrorMessageContainer/ErrorMessageContainer.jsx similarity index 100% rename from src/common/ErrorMessageContainer/ErrorMessageContainer.jsx rename to src/common/components/ErrorMessageContainer/ErrorMessageContainer.jsx diff --git a/src/common/MultiSearchSelect/ControlledMultiSearchSelect.jsx b/src/common/components/MultiSearchSelect/ControlledMultiSearchSelect.jsx similarity index 100% rename from src/common/MultiSearchSelect/ControlledMultiSearchSelect.jsx rename to src/common/components/MultiSearchSelect/ControlledMultiSearchSelect.jsx diff --git a/src/common/MultiSearchSelect/MultiSearchSelect.jsx b/src/common/components/MultiSearchSelect/MultiSearchSelect.jsx similarity index 99% rename from src/common/MultiSearchSelect/MultiSearchSelect.jsx rename to src/common/components/MultiSearchSelect/MultiSearchSelect.jsx index e95bc34..1398d7a 100644 --- a/src/common/MultiSearchSelect/MultiSearchSelect.jsx +++ b/src/common/components/MultiSearchSelect/MultiSearchSelect.jsx @@ -10,7 +10,7 @@ import { IonList, IonSearchbar, IonTitle, - IonToolbar, + IonToolbar } from "@ionic/react"; /** diff --git a/src/common/constants.js b/src/common/constants.js deleted file mode 100644 index 4ef7c5e..0000000 --- a/src/common/constants.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * - * @typedef {Object} SkyPortalInstance - * @property {string} name - The name of the instance - * @property {string} url - The URL of the instance - */ - -/** - * The instances that are available for login - * @type {SkyPortalInstance[]} - */ -export const INSTANCES = [ - { name: "ICARE", url: "https://skyportal-icare.ijclab.in2p3.fr" }, - { name: "FRITZ", url: "https://fritz.science" }, - { name: "FRITZ preview", url: "https://preview.fritz.science" }, -]; - -export const QUERY_PARAMS = { - TOKEN: "token", - INSTANCE: "instance", -}; - -export const QUERY_KEYS = { - CANDIDATES: "candidates", - SOURCES: "sources", - USER_PROFILE: "user", - USER_INFO: "userInfo", - GROUPS: "groups", - SOURCE_PHOTOMETRY: "sourcePhotometry", - CONFIG: "config", - APP_START: "appStart", - BANDPASS_COLORS: "bandpassColors", - SCANNING_PROFILES: "scanningProfiles", - ANNOTATIONS_INFO: "annotationsInfo", - APP_PREFERENCES: "appPreferences", -}; - -/** - * @typedef {"all" | "savedToAllSelected" | "savedToAnySelected" | "savedToAnyAccessible" | "notSavedToAnyAccessible" | "notSavedToAnySelected" | "notSavedToAllSelected"} SavedStatus - */ - -/** - * @type {Object.} - */ -export const SAVED_STATUS = { - ALL: "all", - SAVED_TO_ALL_SELECTED: "savedToAllSelected", - SAVED_TO_ANY_SELECTED: "savedToAnySelected", - SAVED_TO_ANY_ACCESSIBLE: "savedToAnyAccessible", - NOT_SAVED_TO_ANY_ACCESSIBLE: "notSavedToAnyAccessible", - NOT_SAVED_TO_ANY_SELECTED: "notSavedToAnySelected", - NOT_SAVED_TO_ALL_SELECTED: "notSavedToAllSelected", -}; - -export const CANDIDATES_PER_PAGE = 50; diff --git a/src/common/preferences.js b/src/common/preferences.js deleted file mode 100644 index 7de7ffe..0000000 --- a/src/common/preferences.js +++ /dev/null @@ -1,33 +0,0 @@ -import { Preferences } from "@capacitor/preferences"; - -/** - * Set a preference in the app - * @param {string} key - The key to associate with the value being set in preferences. - * @param {any} value - The value to set in preferences with the associated key. - * @returns {Promise} - */ -export async function setPreference(key, value) { - return await Preferences.set({ key, value: JSON.stringify(value) }); -} - -/** - * Get a preference in the app - * @param {string} key - The key to retrieve the value from preferences. - * @returns {Promise} - */ -export async function getPreference(key) { - const pref = await Preferences.get({ key }); - if (pref.value !== null) { - return JSON.parse(pref.value); - } - return null; -} - -/** - * Clear a preference in the app - * @param {string} key - The key to clear from preferences. - * @returns {Promise} - */ -export async function clearPreference(key) { - return await Preferences.remove({ key }); -} diff --git a/src/common/util.js b/src/common/util.js deleted file mode 100644 index 6a1b3ed..0000000 --- a/src/common/util.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Navigate to a new path with params - * @param {import("history").History} history - * @param {string} path - * @param {Object} options - * @param {Record} [options.params] - * @param {any} [options.state] - * @param {boolean} [options.replace] - */ -export const navigateWithParams = ( - history, - path, - { params, state, replace = false }, -) => { - history[replace ? "replace" : "push"]( - `${path}?${new URLSearchParams(params).toString()}`, - state, - ); -}; - -/** - * @typedef {"auto"|"light"|"dark"} DarkMode - */ - -/** - * @param {DarkMode} darkModePreference - * @param {boolean} [systemIsDark] - * @returns {boolean} - */ -export const isActuallyDarkMode = ( - darkModePreference, - systemIsDark = window.matchMedia("(prefers-color-scheme: dark)").matches, -) => { - return ( - darkModePreference === "dark" || - (systemIsDark && darkModePreference === "auto") - ); -}; - -/** - * @param {DarkMode} darkModePreference - * @param {boolean} [systemIsDark] - */ -export const setDarkModeInDocument = ( - darkModePreference, - systemIsDark = window.matchMedia("(prefers-color-scheme: dark)").matches, -) => { - document.documentElement.classList.toggle( - "ion-palette-dark", - isActuallyDarkMode(darkModePreference, systemIsDark), - ); -}; diff --git a/src/events/EventList/EventListScreen.jsx b/src/events/EventList/EventListScreen.jsx deleted file mode 100644 index 2fe1b9b..0000000 --- a/src/events/EventList/EventListScreen.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import "./EventListScreen.scss"; -import { IonHeader, IonPage, IonTitle, IonToolbar } from "@ionic/react"; - -export const EventListScreen = () => { - return ( - - - - Events - - - - ); -}; diff --git a/src/events/EventList/EventListScreen.scss b/src/events/EventList/EventListScreen.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/global.scss b/src/global.scss new file mode 100644 index 0000000..4a9ca60 --- /dev/null +++ b/src/global.scss @@ -0,0 +1,82 @@ +@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"); + +h1, +h2, +h3, +h4, +h5, +h6, +p, +ion-skeleton-text { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +.app-loading { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + background-color: var(--ion-background-color); +} + +form { + .form-section { + margin-bottom: 1rem; + } + + .form-list-header { + padding-left: 2rem; + font-size: 0.7rem; + text-transform: uppercase; + color: var(--ion-color-secondary); + } + + ion-list.list-ios.list-inset { + margin-top: 1.7rem; + margin-bottom: 0.5rem; + } + + .form-list-header + ion-list.list-ios.list-inset { + margin-top: 0.2rem; + } + + ion-list { + background: var(--ion-color-light); + + ion-item { + --background: var(--ion-color-light); + } + + ion-list-header { + font-size: 0.8rem; + font-weight: 800; + + ion-label { + margin-top: 0; + } + } + } + + .error-container { + height: fit-content; + margin: 0.1rem 0; + } +} + +.form-footer { + padding: 0.5rem 1rem var(--ion-safe-area-bottom); + z-index: 2; + width: 100%; + height: auto; + box-shadow: 1px -1px 5px 0 rgba(var(--ion-color-medium-rgb), 0.25); + background: var(--ion-color-light); + + ion-button { + --padding-start: 4rem; + --padding-end: 4rem; + --padding-top: 1rem; + --padding-bottom: 1rem; + } +} diff --git a/src/main.jsx b/src/main.jsx index a909faf..c4b3b19 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -3,16 +3,18 @@ import { createRoot } from "react-dom/client"; import App from "./App"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { IonSpinner } from "@ionic/react"; -import { getPreference } from "./common/preferences.js"; -import { QUERY_KEYS } from "./common/constants.js"; -import { setDarkModeInDocument } from "./common/util.js"; +import { + getPreference, + QUERY_KEYS, + setDarkModeInDocument, +} from "./common/common.lib.js"; const container = document.getElementById("root"); // @ts-ignore const root = createRoot(container); const queryClient = new QueryClient(); (async () => { - /** @type {import("./common/hooks").AppPreferences|null} */ + /** @type {import("./common/common.hooks").AppPreferences|null} */ const appPreferences = await getPreference(QUERY_KEYS.APP_PREFERENCES); const darkMode = appPreferences?.darkMode ?? "auto"; setDarkModeInDocument(darkMode); diff --git a/src/onboarding/CheckQRCodeScreen/CheckQRCodeScreen.scss b/src/onboarding/CheckQRCodeScreen/CheckQRCodeScreen.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/onboarding/OnboardingLower/OnboardingLower.jsx b/src/onboarding/components/OnboardingLower/OnboardingLower.jsx similarity index 91% rename from src/onboarding/OnboardingLower/OnboardingLower.jsx rename to src/onboarding/components/OnboardingLower/OnboardingLower.jsx index 1b18280..0a4b300 100644 --- a/src/onboarding/OnboardingLower/OnboardingLower.jsx +++ b/src/onboarding/components/OnboardingLower/OnboardingLower.jsx @@ -1,23 +1,16 @@ -import { - IonButton, - IonIcon, - IonInput, - IonSelect, - IonSelectOption, -} from "@ionic/react"; +import { IonButton, IonIcon, IonInput, IonSelect, IonSelectOption } from "@ionic/react"; import "./OnboardingLower.scss"; -import { INSTANCES, QUERY_PARAMS } from "../../common/constants.js"; import { useCallback, useState } from "react"; import { qrCode } from "ionicons/icons"; import { CapacitorBarcodeScanner } from "@capacitor/barcode-scanner"; import { Html5QrcodeSupportedFormats } from "html5-qrcode"; import { useHistory } from "react-router"; -import { navigateWithParams } from "../../common/util.js"; +import { INSTANCES, navigateWithParams, QUERY_PARAMS } from "../../../common/common.lib.js"; /** * The lower part of the onboarding screen * @param {Object} props - * @param {import("../auth").OnboardingPage} props.page - The current page of the onboarding screen + * @param {import("../../onboarding.lib.js").OnboardingPage} props.page - The current page of the onboarding screen * @param {Function} props.setPage - The function to set the current page of the onboarding screen * @returns {JSX.Element} */ diff --git a/src/onboarding/OnboardingLower/OnboardingLower.scss b/src/onboarding/components/OnboardingLower/OnboardingLower.scss similarity index 100% rename from src/onboarding/OnboardingLower/OnboardingLower.scss rename to src/onboarding/components/OnboardingLower/OnboardingLower.scss diff --git a/src/onboarding/OnboardingUpper/OnboardingUpper.jsx b/src/onboarding/components/OnboardingUpper/OnboardingUpper.jsx similarity index 84% rename from src/onboarding/OnboardingUpper/OnboardingUpper.jsx rename to src/onboarding/components/OnboardingUpper/OnboardingUpper.jsx index fe03dab..592555a 100644 --- a/src/onboarding/OnboardingUpper/OnboardingUpper.jsx +++ b/src/onboarding/components/OnboardingUpper/OnboardingUpper.jsx @@ -1,15 +1,16 @@ import "./OnboardingUpper.scss"; import { useContext } from "react"; -import { AppContext } from "../../common/context.js"; -import { isActuallyDarkMode } from "../../common/util.js"; +import { AppContext } from "../../../common/common.context.js"; +import { isActuallyDarkMode } from "../../../common/common.lib.js"; /** * @param {Object} props - * @param {import("../auth").OnboardingPage} props.page + * @param {import("../../onboarding.lib.js").OnboardingPage} props.page * @returns {JSX.Element} */ const OnboardingUpper = ({ page }) => { const { darkMode } = useContext(AppContext); + function getTagline() { switch (page) { case "welcome": @@ -32,6 +33,7 @@ const OnboardingUpper = ({ page }) => { ); } } + return (
diff --git a/src/onboarding/OnboardingUpper/OnboardingUpper.scss b/src/onboarding/components/OnboardingUpper/OnboardingUpper.scss similarity index 100% rename from src/onboarding/OnboardingUpper/OnboardingUpper.scss rename to src/onboarding/components/OnboardingUpper/OnboardingUpper.scss diff --git a/src/onboarding/auth.js b/src/onboarding/onboarding.lib.js similarity index 91% rename from src/onboarding/auth.js rename to src/onboarding/onboarding.lib.js index 9ede5a0..c336759 100644 --- a/src/onboarding/auth.js +++ b/src/onboarding/onboarding.lib.js @@ -14,7 +14,7 @@ import { CapacitorHttp } from "@capacitor/core"; * @property {number[]} groupIDs - The IDs of the groups that the profile is associated with * @property {string} timeRange - The time range of the profile * @property {string} [sortingKey] - The key to use to sort the profile - * @property {import("../common/constants.js").SavedStatus} savedStatus - The status of the profile + * @property {import("../common/common.lib.js").SavedStatus} savedStatus - The status of the profile * @property {string} [sortingOrder] - The order to use to sort the profile * @property {string} [sortingOrigin] - The origin of the sorting * @property {string} rejectedStatus - The status of the rejected @@ -41,7 +41,7 @@ import { CapacitorHttp } from "@capacitor/core"; /** * @typedef {Object} UserInfo * @property {string} token - The token of the user - * @property {import("../common/constants.js").SkyPortalInstance} instance - The instance of the user + * @property {import("../common/common.lib.js").SkyPortalInstance} instance - The instance of the user */ /** diff --git a/src/onboarding/CheckQRCodeScreen/CheckQRCodeScreen.jsx b/src/onboarding/screens/CheckQRCodeScreen/CheckQRCodeScreen.jsx similarity index 86% rename from src/onboarding/CheckQRCodeScreen/CheckQRCodeScreen.jsx rename to src/onboarding/screens/CheckQRCodeScreen/CheckQRCodeScreen.jsx index 4ea96e4..8826b78 100644 --- a/src/onboarding/CheckQRCodeScreen/CheckQRCodeScreen.jsx +++ b/src/onboarding/screens/CheckQRCodeScreen/CheckQRCodeScreen.jsx @@ -2,11 +2,14 @@ import { IonContent, IonPage, IonSpinner } from "@ionic/react"; import "./CheckQRCodeScreen.scss"; import { useHistory, useLocation } from "react-router"; import { useContext, useEffect, useState } from "react"; -import { fetchUserProfile } from "../auth.js"; -import { QUERY_KEYS, QUERY_PARAMS } from "../../common/constants.js"; -import { setPreference } from "../../common/preferences.js"; +import { fetchUserProfile } from "../../onboarding.lib.js"; import { useMutation } from "@tanstack/react-query"; -import { UserContext } from "../../common/context.js"; +import { UserContext } from "../../../common/common.context.js"; +import { + QUERY_KEYS, + QUERY_PARAMS, + setPreference, +} from "../../../common/common.lib.js"; export const CheckQRCodeScreen = () => { const history = useHistory(); diff --git a/src/onboarding/LoginOk/LoginOkScreen.jsx b/src/onboarding/screens/LoginOkScreen/LoginOkScreen.jsx similarity index 94% rename from src/onboarding/LoginOk/LoginOkScreen.jsx rename to src/onboarding/screens/LoginOkScreen/LoginOkScreen.jsx index b6426ad..bc58a02 100644 --- a/src/onboarding/LoginOk/LoginOkScreen.jsx +++ b/src/onboarding/screens/LoginOkScreen/LoginOkScreen.jsx @@ -3,7 +3,7 @@ import "./LoginOkScreen.scss"; import { checkmarkCircleSharp } from "ionicons/icons"; import { useEffect } from "react"; import { useHistory } from "react-router"; -import { useUserProfile } from "../../common/hooks.js"; +import { useUserProfile } from "../../../common/common.hooks.js"; export const LoginOkScreen = () => { const history = useHistory(); diff --git a/src/onboarding/LoginOk/LoginOkScreen.scss b/src/onboarding/screens/LoginOkScreen/LoginOkScreen.scss similarity index 100% rename from src/onboarding/LoginOk/LoginOkScreen.scss rename to src/onboarding/screens/LoginOkScreen/LoginOkScreen.scss diff --git a/src/onboarding/OnboardingScreen/OnboardingScreen.jsx b/src/onboarding/screens/OnboardingScreen/OnboardingScreen.jsx similarity index 68% rename from src/onboarding/OnboardingScreen/OnboardingScreen.jsx rename to src/onboarding/screens/OnboardingScreen/OnboardingScreen.jsx index 0f9547d..3ab6673 100644 --- a/src/onboarding/OnboardingScreen/OnboardingScreen.jsx +++ b/src/onboarding/screens/OnboardingScreen/OnboardingScreen.jsx @@ -1,11 +1,11 @@ import { IonContent, IonPage } from "@ionic/react"; -import OnboardingUpper from "../OnboardingUpper/OnboardingUpper.jsx"; -import OnboardingLower from "../OnboardingLower/OnboardingLower.jsx"; +import OnboardingUpper from "../../components/OnboardingUpper/OnboardingUpper.jsx"; +import OnboardingLower from "../../components/OnboardingLower/OnboardingLower.jsx"; import "./OnboardingScreen.scss"; import { useState } from "react"; const OnboardingScreen = () => { - /** @type {[import("../auth").OnboardingPage, Function]} */ + /** @type {[import("../../onboarding.lib.js").OnboardingPage, Function]} */ const [page, setPage] = useState("welcome"); return ( diff --git a/src/onboarding/OnboardingScreen/OnboardingScreen.scss b/src/onboarding/screens/OnboardingScreen/OnboardingScreen.scss similarity index 100% rename from src/onboarding/OnboardingScreen/OnboardingScreen.scss rename to src/onboarding/screens/OnboardingScreen/OnboardingScreen.scss diff --git a/src/scanning/scanningHooks.js b/src/scanning/scanning.hooks.js similarity index 74% rename from src/scanning/scanningHooks.js rename to src/scanning/scanning.hooks.js index 308f7a4..cc4b5f2 100644 --- a/src/scanning/scanningHooks.js +++ b/src/scanning/scanning.hooks.js @@ -1,13 +1,13 @@ import { useInfiniteQuery, useQuery } from "@tanstack/react-query"; -import { CANDIDATES_PER_PAGE, QUERY_KEYS } from "../common/constants.js"; -import { fetchAnnotationInfo, searchCandidates } from "./scanningRequests.js"; -import { fetchUserProfile } from "../onboarding/auth.js"; +import { fetchAnnotationInfo, searchCandidates } from "./scanning.requests.js"; +import { fetchUserProfile } from "../onboarding/onboarding.lib.js"; import { useContext } from "react"; -import { UserContext } from "../common/context.js"; +import { UserContext } from "../common/common.context.js"; import { useLocation } from "react-router"; +import { CANDIDATES_PER_PAGE, QUERY_KEYS } from "../common/common.lib.js"; /** - * @returns {import("@tanstack/react-query").UseInfiniteQueryResult, Error>} + * @returns {import("@tanstack/react-query").UseInfiniteQueryResult, Error>} */ export const useSearchCandidates = () => { const { userInfo } = useContext(UserContext); @@ -17,7 +17,7 @@ export const useSearchCandidates = () => { let startDate = ""; /** @type {string} */ let endDate = ""; - /** @type {import("../common/constants.js").SavedStatus} */ + /** @type {import("../common/common.lib.js").SavedStatus} */ let savedStatus = "all"; /** @type {number[]} */ let groupIDs = []; @@ -66,10 +66,10 @@ export const useSearchCandidates = () => { }; /** - * @param {import("../onboarding/auth.js").UserInfo} userInfo - * @returns {{profiles: import("../onboarding/auth.js").ScanningProfile[] | undefined, status: import("@tanstack/react-query").QueryStatus, error: any | undefined}} + * @returns {{profiles: import("../onboarding/onboarding.lib.js").ScanningProfile[] | undefined, status: import("@tanstack/react-query").QueryStatus, error: any | undefined}} */ -export const useScanningProfiles = (userInfo) => { +export const useScanningProfiles = () => { + const userInfo = useContext(UserContext); const { data: profiles, status, @@ -89,7 +89,7 @@ export const useScanningProfiles = (userInfo) => { }; /** - * @returns {{annotationsInfo: import("./scanningRequests.js").AnnotationsInfo | undefined, status: import("@tanstack/react-query").QueryStatus, error: any | undefined }} + * @returns {{annotationsInfo: import("./scanning.requests.js").AnnotationsInfo | undefined, status: import("@tanstack/react-query").QueryStatus, error: any | undefined }} */ export const useAnnotationsInfo = () => { const { userInfo } = useContext(UserContext); diff --git a/src/scanning/scanningLib.js b/src/scanning/scanning.lib.js similarity index 97% rename from src/scanning/scanningLib.js rename to src/scanning/scanning.lib.js index c7d75f3..a28c551 100644 --- a/src/scanning/scanningLib.js +++ b/src/scanning/scanning.lib.js @@ -71,7 +71,7 @@ * @typedef {Object} ScanningConfig * @property {string} startDate * @property {string} endDate - * @property {import("../common/constants").SavedStatus} savedStatus + * @property {import("../common/common.lib.js").SavedStatus} savedStatus * @property {DiscardBehavior} discardBehavior * @property {number[]} saveGroupIds * @property {Group[]} saveGroups @@ -94,7 +94,8 @@ import { Clipboard } from "@capacitor/clipboard"; import { useIonToast } from "@ionic/react"; import { useCallback } from "react"; import moment from "moment-timezone"; -import { SAVED_STATUS } from "../common/constants.js"; + +import { SAVED_STATUS } from "../common/common.lib.js"; /** * @type {Object} @@ -186,7 +187,7 @@ export function getThumbnailImageUrl(candidate, type) { * @param {Photometry[]} params.photometry * @param {number} params.titleFontSize * @param {number} params.labelFontSize - * @param {import("../common/requests").BandpassesColors} params.bandpassesColors + * @param {import("../common/common.requests.js").BandpassesColors} params.bandpassesColors * @returns {import("vega-embed").VisualizationSpec} */ export const getVegaPlotSpec = ({ @@ -452,7 +453,7 @@ export const parseIntList = (intListString) => { /** * - * @param {import("../onboarding/auth").ScanningProfile} scanningProfile + * @param {import("../onboarding/onboarding.lib.js").ScanningProfile} scanningProfile * @returns {string} */ export const getStartDate = (scanningProfile) => { @@ -466,7 +467,7 @@ export const getStartDate = (scanningProfile) => { }; /** - * @param {import("../onboarding/auth").ScanningProfile} scanningProfile + * @param {import("../onboarding/onboarding.lib.js").ScanningProfile} scanningProfile */ export const getFiltering = (scanningProfile) => { switch (scanningProfile.savedStatus) { @@ -510,7 +511,7 @@ export const getFiltering = (scanningProfile) => { * @param {boolean} data.filterCandidates * @param {string} data.filteringType * @param {string} data.filteringAnyOrAll - * @returns {import("../common/constants.js").SavedStatus} + * @returns {import("../common/common.lib.js").SavedStatus} */ export const computeSavedStatus = ({ filterCandidates, diff --git a/src/scanning/scanningRequests.js b/src/scanning/scanning.requests.js similarity index 81% rename from src/scanning/scanningRequests.js rename to src/scanning/scanning.requests.js index a0dec80..f857d2a 100644 --- a/src/scanning/scanningRequests.js +++ b/src/scanning/scanning.requests.js @@ -1,10 +1,10 @@ import { CapacitorHttp } from "@capacitor/core"; -import { CANDIDATES_PER_PAGE } from "../common/constants.js"; -import { fetchUserProfile } from "../onboarding/auth.js"; +import { fetchUserProfile } from "../onboarding/onboarding.lib.js"; +import { CANDIDATES_PER_PAGE } from "../common/common.lib.js"; /** * @typedef {Object} CandidateSearchResponse - * @property {import("./scanningLib.js").Candidate[]} candidates - The candidates + * @property {import("./scanning.lib.js").Candidate[]} candidates - The candidates * @property {number} totalMatches - The total matches * @property {string} queryID - The query ID * @property {string} pageNumber - The page number @@ -21,10 +21,10 @@ import { fetchUserProfile } from "../onboarding/auth.js"; /** * Returns the candidates from the API * @param {Object} params - * @param {import("../onboarding/auth.js").UserInfo} params.userInfo - The user info + * @param {import("../onboarding/onboarding.lib.js").UserInfo} params.userInfo - The user info * @param {string} params.startDate - The start date of the candidates * @param {string|null} [params.endDate=null] - The end date of the candidates - * @param {import("../common/constants").SavedStatus} params.savedStatus - The saved status of the candidates + * @param {import("../common/common.lib.js").SavedStatus} params.savedStatus - The saved status of the candidates * @param {number[]} params.groupIDs - The group IDs to search for * @param {string|null} [params.queryID=null] - The query ID * @param {number} params.pageNumber - The page number @@ -67,8 +67,8 @@ export async function searchCandidates({ } /** - * @param {import("../onboarding/auth.js").UserInfo} userInfo - * @returns {Promise} + * @param {import("../onboarding/onboarding.lib.js").UserInfo} userInfo + * @returns {Promise} */ export async function fetchGroups(userInfo) { let response = await CapacitorHttp.get({ @@ -84,11 +84,11 @@ export async function fetchGroups(userInfo) { * Fetch the photometry of a source * @param {Object} params * @param {string} params.sourceId - The source ID - * @param {import("../onboarding/auth.js").UserInfo} params.userInfo - The user info + * @param {import("../onboarding/onboarding.lib.js").UserInfo} params.userInfo - The user info * @param {string} [params.includeOwnerInfo="true"] - Include owner info * @param {string} [params.includeStreamInfo="true"] - Include stream info * @param {string} [params.includeValidationInfo="true"] - Include validation info - * @returns {Promise} + * @returns {Promise} */ export const fetchSourcePhotometry = async ({ sourceId, @@ -113,7 +113,7 @@ export const fetchSourcePhotometry = async ({ /** * @param {Object} params - * @param {import("../onboarding/auth.js").UserInfo} params.userInfo + * @param {import("../onboarding/onboarding.lib.js").UserInfo} params.userInfo * @param {string} params.sourceId * @param {number[]} params.groupIds * @returns {Promise} @@ -135,8 +135,8 @@ export const addSourceToGroups = async ({ userInfo, sourceId, groupIds }) => { /** * @param {Object} params - * @param {import("../onboarding/auth.js").UserInfo} params.userInfo - * @param {import("../onboarding/auth.js").ScanningProfile} params.profile + * @param {import("../onboarding/onboarding.lib.js").UserInfo} params.userInfo + * @param {import("../onboarding/onboarding.lib.js").ScanningProfile} params.profile * @returns {Promise<*>} */ export const createNewProfile = async ({ userInfo, profile }) => { @@ -164,7 +164,7 @@ export const createNewProfile = async ({ userInfo, profile }) => { /** * @param {Object} params - * @param {import("../onboarding/auth.js").UserInfo} params.userInfo + * @param {import("../onboarding/onboarding.lib.js").UserInfo} params.userInfo * @returns {Promise} */ export const fetchAnnotationInfo = async ({ userInfo }) => { diff --git a/src/scanning/scanningOptions/ScanningHome/ScanningHome.scss b/src/scanning/scanningOptions/ScanningHome/ScanningHome.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/scanning/scanningOptions/ScanningOptionsDate/ScanningOptionsDate.scss b/src/scanning/scanningOptions/ScanningOptionsDate/ScanningOptionsDate.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/scanning/scanningOptions/ScanningOptionsDiscarding/ScanningOptionsDiscarding.scss b/src/scanning/scanningOptions/ScanningOptionsDiscarding/ScanningOptionsDiscarding.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/scanning/scanningOptions/ScanningOptionsProgram/ScanningOptionsProgram.scss b/src/scanning/scanningOptions/ScanningOptionsProgram/ScanningOptionsProgram.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/scanning/scanningOptions/CandidateFiltering/CandidateFiltering.jsx b/src/scanning/scanningOptions/components/CandidateFiltering/CandidateFiltering.jsx similarity index 100% rename from src/scanning/scanningOptions/CandidateFiltering/CandidateFiltering.jsx rename to src/scanning/scanningOptions/components/CandidateFiltering/CandidateFiltering.jsx diff --git a/src/scanning/scanningOptions/CandidateFiltering/CandidateFiltering.scss b/src/scanning/scanningOptions/components/CandidateFiltering/CandidateFiltering.scss similarity index 100% rename from src/scanning/scanningOptions/CandidateFiltering/CandidateFiltering.scss rename to src/scanning/scanningOptions/components/CandidateFiltering/CandidateFiltering.scss diff --git a/src/scanning/scanningOptions/PinnedAnnotationsPicker/PinnedAnnotationsPicker.jsx b/src/scanning/scanningOptions/components/PinnedAnnotationsPicker/PinnedAnnotationsPicker.jsx similarity index 96% rename from src/scanning/scanningOptions/PinnedAnnotationsPicker/PinnedAnnotationsPicker.jsx rename to src/scanning/scanningOptions/components/PinnedAnnotationsPicker/PinnedAnnotationsPicker.jsx index 1c26608..5bc41d8 100644 --- a/src/scanning/scanningOptions/PinnedAnnotationsPicker/PinnedAnnotationsPicker.jsx +++ b/src/scanning/scanningOptions/components/PinnedAnnotationsPicker/PinnedAnnotationsPicker.jsx @@ -11,14 +11,14 @@ import { IonSearchbar, IonText, IonTitle, - IonToolbar, + IonToolbar } from "@ionic/react"; import { useCallback, useState } from "react"; -import { getAnnotationId } from "../../scanningLib.js"; +import { getAnnotationId } from "../../../scanning.lib.js"; /** * @param {Object} props - * @param {import("../../scanningRequests").AnnotationsInfo} props.annotationsInfo + * @param {import("../../../scanning.requests.js").AnnotationsInfo} props.annotationsInfo * @param {string[]} props.selectedAnnotationKeys * @param {React.MutableRefObject} props.modal * @param {number} [props.limit=3] diff --git a/src/scanning/scanningOptions/ProfileListItem/ProfileListItem.jsx b/src/scanning/scanningOptions/components/ProfileListItem/ProfileListItem.jsx similarity index 86% rename from src/scanning/scanningOptions/ProfileListItem/ProfileListItem.jsx rename to src/scanning/scanningOptions/components/ProfileListItem/ProfileListItem.jsx index cb394d9..026e513 100644 --- a/src/scanning/scanningOptions/ProfileListItem/ProfileListItem.jsx +++ b/src/scanning/scanningOptions/components/ProfileListItem/ProfileListItem.jsx @@ -6,18 +6,18 @@ import { IonItemOption, IonItemOptions, IonItemSliding, - IonLabel, + IonLabel } from "@ionic/react"; import { trash } from "ionicons/icons"; import { useRef } from "react"; /** * @param {Object} props - * @param {import("../../../onboarding/auth").ScanningProfile} props.profile - * @param {import("../../scanningLib").Group[]} props.userAccessibleGroups + * @param {import("../../../../onboarding/onboarding.lib.js").ScanningProfile} props.profile + * @param {import("../../../scanning.lib.js").Group[]} props.userAccessibleGroups * @param {boolean} [props.itemSliding=false] * @param {() => void} [props.onClick] - * @param {(profile: import("../../../onboarding/auth").ScanningProfile) => void} [props.onDelete] + * @param {(profile: import("../../../../onboarding/onboarding.lib.js").ScanningProfile) => void} [props.onDelete] * @returns {JSX.Element} */ export const ProfileListItem = ({ diff --git a/src/scanning/scanningOptions/RecentProfiles/RecentProfiles.jsx b/src/scanning/scanningOptions/components/RecentProfiles/RecentProfiles.jsx similarity index 85% rename from src/scanning/scanningOptions/RecentProfiles/RecentProfiles.jsx rename to src/scanning/scanningOptions/components/RecentProfiles/RecentProfiles.jsx index cc133b8..24cca49 100644 --- a/src/scanning/scanningOptions/RecentProfiles/RecentProfiles.jsx +++ b/src/scanning/scanningOptions/components/RecentProfiles/RecentProfiles.jsx @@ -1,25 +1,23 @@ import "./RecentProfiles.scss"; import { IonButton, IonIcon, IonList, IonLoading, IonText } from "@ionic/react"; -import { useUserAccessibleGroups } from "../../../common/hooks.js"; -import { useCallback, useContext } from "react"; -import { UserContext } from "../../../common/context.js"; -import { navigateWithParams } from "../../../common/util.js"; +import { useUserAccessibleGroups } from "../../../../common/common.hooks.js"; +import { useCallback } from "react"; +import { navigateWithParams } from "../../../../common/common.lib.js"; import { useHistory } from "react-router"; -import { useScanningProfiles } from "../../scanningHooks.js"; +import { useScanningProfiles } from "../../../scanning.hooks.js"; import { ProfileListItem } from "../ProfileListItem/ProfileListItem.jsx"; import { chevronForwardOutline } from "ionicons/icons"; export const RecentProfiles = () => { const history = useHistory(); - const { userInfo } = useContext(UserContext); - const { profiles } = useScanningProfiles(userInfo); + const { profiles } = useScanningProfiles(); const { userAccessibleGroups } = useUserAccessibleGroups(); const defaultProfileIndex = profiles?.findIndex((profile) => profile.default); const handleScanWithProfile = useCallback( /** - * @param {import("../../../onboarding/auth").ScanningProfile} profile + * @param {import("../../../../onboarding/onboarding.lib.js").ScanningProfile} profile */ (profile) => { navigateWithParams(history, "/scanning", { @@ -47,15 +45,15 @@ export const RecentProfiles = () => { }; return ( -
-
+
+

Recent profiles

See all
-
+
{profiles && userAccessibleGroups && ( <> {profiles.length > 0 && defaultProfileIndex && ( diff --git a/src/scanning/scanningOptions/RecentProfiles/RecentProfiles.scss b/src/scanning/scanningOptions/components/RecentProfiles/RecentProfiles.scss similarity index 87% rename from src/scanning/scanningOptions/RecentProfiles/RecentProfiles.scss rename to src/scanning/scanningOptions/components/RecentProfiles/RecentProfiles.scss index ee0e302..3d5f672 100644 --- a/src/scanning/scanningOptions/RecentProfiles/RecentProfiles.scss +++ b/src/scanning/scanningOptions/components/RecentProfiles/RecentProfiles.scss @@ -1,17 +1,17 @@ -.scanning-profiles { +.recent-profiles { display: grid; grid-template-rows: auto 1fr auto; height: 100%; padding-bottom: calc(55px + #{var(--ion-safe-area-bottom)} + 1rem); - .sp-header { + .recent-profiles-header { display: flex; justify-content: space-between; align-items: center; padding: 0 1rem; } - .sp-content { + .recent-profiles-content { .hint-container { display: flex; align-items: center; diff --git a/src/scanning/scanningOptions/ScanningOptionsDate/ScanningOptionsDate.jsx b/src/scanning/scanningOptions/components/ScanningOptionsDate/ScanningOptionsDate.jsx similarity index 90% rename from src/scanning/scanningOptions/ScanningOptionsDate/ScanningOptionsDate.jsx rename to src/scanning/scanningOptions/components/ScanningOptionsDate/ScanningOptionsDate.jsx index 5c77d1d..7e1bac7 100644 --- a/src/scanning/scanningOptions/ScanningOptionsDate/ScanningOptionsDate.jsx +++ b/src/scanning/scanningOptions/components/ScanningOptionsDate/ScanningOptionsDate.jsx @@ -1,14 +1,8 @@ import "./ScanningOptionsDate.scss"; -import { - IonDatetimeButton, - IonItem, - IonLabel, - IonList, - IonModal, -} from "@ionic/react"; +import { IonDatetimeButton, IonItem, IonLabel, IonList, IonModal } from "@ionic/react"; import moment from "moment-timezone"; -import { ControlledDateTime } from "../../../common/ControlledDateTime/ControlledDateTime.jsx"; -import { ErrorMessageContainer } from "../../../common/ErrorMessageContainer/ErrorMessageContainer.jsx"; +import { ControlledDateTime } from "../../../../common/components/ControlledDateTime/ControlledDateTime.jsx"; +import { ErrorMessageContainer } from "../../../../common/components/ErrorMessageContainer/ErrorMessageContainer.jsx"; /** * Date selection section of the scanning options diff --git a/src/scanning/scanningOptions/ScanningOptionsDiscarding/ScanningOptionsDiscarding.jsx b/src/scanning/scanningOptions/components/ScanningOptionsDiscarding/ScanningOptionsDiscarding.jsx similarity index 87% rename from src/scanning/scanningOptions/ScanningOptionsDiscarding/ScanningOptionsDiscarding.jsx rename to src/scanning/scanningOptions/components/ScanningOptionsDiscarding/ScanningOptionsDiscarding.jsx index 88af04a..9f8fec2 100644 --- a/src/scanning/scanningOptions/ScanningOptionsDiscarding/ScanningOptionsDiscarding.jsx +++ b/src/scanning/scanningOptions/components/ScanningOptionsDiscarding/ScanningOptionsDiscarding.jsx @@ -8,11 +8,13 @@ import { IonList, IonModal, IonSelect, - IonSelectOption, + IonSelectOption } from "@ionic/react"; -import { ControlledMultiSearchSelect } from "../../../common/MultiSearchSelect/ControlledMultiSearchSelect.jsx"; +import { + ControlledMultiSearchSelect +} from "../../../../common/components/MultiSearchSelect/ControlledMultiSearchSelect.jsx"; import { pencil } from "ionicons/icons"; -import { ErrorMessageContainer } from "../../../common/ErrorMessageContainer/ErrorMessageContainer.jsx"; +import { ErrorMessageContainer } from "../../../../common/components/ErrorMessageContainer/ErrorMessageContainer.jsx"; /** * Discarding section of the scanning options @@ -21,7 +23,7 @@ import { ErrorMessageContainer } from "../../../common/ErrorMessageContainer/Err * @param {Partial>> & {root?: Record & import("react-hook-form").GlobalError}} props.errors * @param {import("react-hook-form").Control} props.control * @param {import("react-hook-form").UseFormWatch} props.watch - * @param {import("../../scanningLib.js").Group[]} props.userAccessibleGroups + * @param {import("../../../scanning.lib.js").Group[]} props.userAccessibleGroups * @param {React.MutableRefObject} props.modal * @returns {JSX.Element} */ @@ -33,7 +35,7 @@ export const ScanningOptionsDiscarding = ({ userAccessibleGroups, modal, }) => { - /** @type {import("../../scanningLib.js").Group[]} */ + /** @type {import("../../../scanning.lib.js").Group[]} */ const junkGroups = watch("junkGroups").map( (/** @type {string[]} */ groupId) => userAccessibleGroups.find((group) => group.id === +groupId), @@ -56,7 +58,9 @@ export const ScanningOptionsDiscarding = ({ {junkGroups.length > 0 && ( {junkGroups.map( - (/** @type {import("../../scanningLib.js").Group} */ group) => ( + ( + /** @type {import("../../../scanning.lib.js").Group} */ group, + ) => ( {group.name} ), )} @@ -99,7 +103,7 @@ export const ScanningOptionsDiscarding = ({ > {junkGroups.map( ( - /** @type {import("../../scanningLib.js").Group} */ group, + /** @type {import("../../../scanning.lib.js").Group} */ group, ) => ( {group.name} diff --git a/src/scanning/scanningOptions/ScanningOptionsForm/ScanningOptionsForm.jsx b/src/scanning/scanningOptions/components/ScanningOptionsForm/ScanningOptionsForm.jsx similarity index 93% rename from src/scanning/scanningOptions/ScanningOptionsForm/ScanningOptionsForm.jsx rename to src/scanning/scanningOptions/components/ScanningOptionsForm/ScanningOptionsForm.jsx index cbc93e9..c25fd06 100644 --- a/src/scanning/scanningOptions/ScanningOptionsForm/ScanningOptionsForm.jsx +++ b/src/scanning/scanningOptions/components/ScanningOptionsForm/ScanningOptionsForm.jsx @@ -9,18 +9,18 @@ import { useContext, useRef } from "react"; import { useUserAccessibleGroups, useUserProfile, -} from "../../../common/hooks.js"; +} from "../../../../common/common.hooks.js"; import { useHistory, useParams } from "react-router"; import { useMutation } from "@tanstack/react-query"; -import { searchCandidates } from "../../scanningRequests.js"; +import { searchCandidates } from "../../../scanning.requests.js"; import { computeSavedStatus, getDefaultValues, getFiltering, getStartDate, -} from "../../scanningLib.js"; +} from "../../../scanning.lib.js"; import { ScanningOptionsPinnedAnnotations } from "../ScanningOptionsPinnedAnnotations/ScanningOptionsPinnedAnnotations.jsx"; -import { UserContext } from "../../../common/context.js"; +import { UserContext } from "../../../../common/common.context.js"; export const ScanningOptionsForm = () => { const { userInfo } = useContext(UserContext); @@ -28,7 +28,7 @@ export const ScanningOptionsForm = () => { /** @type {any} */ const { /** @type {string|undefined} */ profile: profileName } = useParams(); const { userProfile } = useUserProfile(); - /** @type {import("../../../onboarding/auth.js").ScanningProfile|undefined}*/ + /** @type {import("../../../../onboarding/onboarding.lib.js").ScanningProfile|undefined}*/ const scanningProfile = userProfile?.preferences?.scanningProfiles?.find( (profile) => profile.name === profileName, ); @@ -60,7 +60,7 @@ export const ScanningOptionsForm = () => { /** * @param {Object} params * @param {number[]} params.saveGroupIds - * @param {import("../../../common/constants.js").SavedStatus} params.savedStatus + * @param {import("../../../../common/common.lib.js").SavedStatus} params.savedStatus * @param {string} params.startDate * @param {string} params.endDate * @returns {Promise} diff --git a/src/scanning/scanningOptions/ScanningOptionsForm/ScanningOptionsForm.scss b/src/scanning/scanningOptions/components/ScanningOptionsForm/ScanningOptionsForm.scss similarity index 100% rename from src/scanning/scanningOptions/ScanningOptionsForm/ScanningOptionsForm.scss rename to src/scanning/scanningOptions/components/ScanningOptionsForm/ScanningOptionsForm.scss diff --git a/src/scanning/scanningOptions/ScanningOptionsPinnedAnnotations/ScanningOptionsPinnedAnnotations.jsx b/src/scanning/scanningOptions/components/ScanningOptionsPinnedAnnotations/ScanningOptionsPinnedAnnotations.jsx similarity index 89% rename from src/scanning/scanningOptions/ScanningOptionsPinnedAnnotations/ScanningOptionsPinnedAnnotations.jsx rename to src/scanning/scanningOptions/components/ScanningOptionsPinnedAnnotations/ScanningOptionsPinnedAnnotations.jsx index 675561f..a01484f 100644 --- a/src/scanning/scanningOptions/ScanningOptionsPinnedAnnotations/ScanningOptionsPinnedAnnotations.jsx +++ b/src/scanning/scanningOptions/components/ScanningOptionsPinnedAnnotations/ScanningOptionsPinnedAnnotations.jsx @@ -1,16 +1,9 @@ -import { - IonButton, - IonIcon, - IonItem, - IonLabel, - IonList, - IonModal, -} from "@ionic/react"; -import { useAnnotationsInfo } from "../../scanningHooks.js"; +import { IonButton, IonIcon, IonItem, IonLabel, IonList, IonModal } from "@ionic/react"; +import { useAnnotationsInfo } from "../../../scanning.hooks.js"; import { pencil } from "ionicons/icons"; import { PinnedAnnotationsPicker } from "../PinnedAnnotationsPicker/PinnedAnnotationsPicker.jsx"; import { Controller } from "react-hook-form"; -import { extractAnnotationOriginAndKey } from "../../scanningLib.js"; +import { extractAnnotationOriginAndKey } from "../../../scanning.lib.js"; /** * @param {Object} props diff --git a/src/scanning/scanningOptions/ScanningOptionsProgram/ScanningOptionsProgram.jsx b/src/scanning/scanningOptions/components/ScanningOptionsProgram/ScanningOptionsProgram.jsx similarity index 86% rename from src/scanning/scanningOptions/ScanningOptionsProgram/ScanningOptionsProgram.jsx rename to src/scanning/scanningOptions/components/ScanningOptionsProgram/ScanningOptionsProgram.jsx index 934ca99..8ee1ea5 100644 --- a/src/scanning/scanningOptions/ScanningOptionsProgram/ScanningOptionsProgram.jsx +++ b/src/scanning/scanningOptions/components/ScanningOptionsProgram/ScanningOptionsProgram.jsx @@ -1,24 +1,17 @@ import "./ScanningOptionsProgram.scss"; -import { - IonButton, - IonChip, - IonIcon, - IonItem, - IonLabel, - IonList, - IonModal, - IonToggle, -} from "@ionic/react"; +import { IonButton, IonChip, IonIcon, IonItem, IonLabel, IonList, IonModal, IonToggle } from "@ionic/react"; import { pencil } from "ionicons/icons"; -import { ControlledMultiSearchSelect } from "../../../common/MultiSearchSelect/ControlledMultiSearchSelect.jsx"; +import { + ControlledMultiSearchSelect +} from "../../../../common/components/MultiSearchSelect/ControlledMultiSearchSelect.jsx"; import { Controller } from "react-hook-form"; import { CandidateFiltering } from "../CandidateFiltering/CandidateFiltering.jsx"; -import { ErrorMessageContainer } from "../../../common/ErrorMessageContainer/ErrorMessageContainer.jsx"; +import { ErrorMessageContainer } from "../../../../common/components/ErrorMessageContainer/ErrorMessageContainer.jsx"; /** * Program selection section of the scanning options * @param {Object} props - * @param {import("../../scanningLib.js").Group[]} props.userAccessibleGroups + * @param {import("../../../scanning.lib.js").Group[]} props.userAccessibleGroups * @param {React.MutableRefObject} props.modal * @param {import("react-hook-form").Control} props.control * @param {import("react-hook-form").UseFormWatch} props.watch @@ -61,7 +54,9 @@ export const ScanningOptionsProgram = ({ userAccessibleGroups.find((group) => group.id === +groupId), ) .map( - (/** @type {import("../../scanningLib.js").Group} */ group) => ( + ( + /** @type {import("../../../scanning.lib.js").Group} */ group, + ) => ( {group.name} ), )} diff --git a/src/scanning/scanningOptions/ScanningProfileCreator/ScanningProfileCreator.jsx b/src/scanning/scanningOptions/components/ScanningProfileCreator/ScanningProfileCreator.jsx similarity index 85% rename from src/scanning/scanningOptions/ScanningProfileCreator/ScanningProfileCreator.jsx rename to src/scanning/scanningOptions/components/ScanningProfileCreator/ScanningProfileCreator.jsx index 7581e2c..b4bd01e 100644 --- a/src/scanning/scanningOptions/ScanningProfileCreator/ScanningProfileCreator.jsx +++ b/src/scanning/scanningOptions/components/ScanningProfileCreator/ScanningProfileCreator.jsx @@ -2,13 +2,13 @@ import "./ScanningProfileCreator.scss"; import { ScanningOptionsProgram } from "../ScanningOptionsProgram/ScanningOptionsProgram.jsx"; import { IonButton, IonItem, IonList, useIonAlert } from "@ionic/react"; import { useForm } from "react-hook-form"; -import { computeSavedStatus, getDefaultValues } from "../../scanningLib.js"; -import { useUserAccessibleGroups } from "../../../common/hooks.js"; +import { computeSavedStatus, getDefaultValues } from "../../../scanning.lib.js"; +import { useUserAccessibleGroups } from "../../../../common/common.hooks.js"; import { useContext, useRef } from "react"; -import { UserContext } from "../../../common/context.js"; -import { ErrorMessageContainer } from "../../../common/ErrorMessageContainer/ErrorMessageContainer.jsx"; -import { ControlledInput } from "../../../common/ControlledInput/ControlledInput.jsx"; -import { createNewProfile } from "../../scanningRequests.js"; +import { UserContext } from "../../../../common/common.context.js"; +import { ErrorMessageContainer } from "../../../../common/components/ErrorMessageContainer/ErrorMessageContainer.jsx"; +import { ControlledInput } from "../../../../common/components/ControlledInput/ControlledInput.jsx"; +import { createNewProfile } from "../../../scanning.requests.js"; import { useHistory } from "react-router"; export const ScanningProfileCreator = () => { @@ -41,7 +41,7 @@ export const ScanningProfileCreator = () => { }); return; } - /** @type {import("../../../onboarding/auth").ScanningProfile} */ + /** @type {import("../../../../onboarding/onboarding.lib.js").ScanningProfile} */ const profile = { name: data.profileName, default: true, diff --git a/src/scanning/scanningOptions/ScanningProfileCreator/ScanningProfileCreator.scss b/src/scanning/scanningOptions/components/ScanningProfileCreator/ScanningProfileCreator.scss similarity index 100% rename from src/scanning/scanningOptions/ScanningProfileCreator/ScanningProfileCreator.scss rename to src/scanning/scanningOptions/components/ScanningProfileCreator/ScanningProfileCreator.scss diff --git a/src/scanning/scanningOptions/ScanningHome/ScanningHome.jsx b/src/scanning/scanningOptions/screens/ScanningHomeTab/ScanningHomeTab.jsx similarity index 70% rename from src/scanning/scanningOptions/ScanningHome/ScanningHome.jsx rename to src/scanning/scanningOptions/screens/ScanningHomeTab/ScanningHomeTab.jsx index 2fb940e..7db211a 100644 --- a/src/scanning/scanningOptions/ScanningHome/ScanningHome.jsx +++ b/src/scanning/scanningOptions/screens/ScanningHomeTab/ScanningHomeTab.jsx @@ -1,8 +1,7 @@ -import "./ScanningHome.scss"; import { IonContent, IonHeader, IonTitle, IonToolbar } from "@ionic/react"; -import { RecentProfiles } from "../RecentProfiles/RecentProfiles.jsx"; +import { RecentProfiles } from "../../components/RecentProfiles/RecentProfiles.jsx"; -export const ScanningHome = () => { +export const ScanningHomeTab = () => { return ( <> diff --git a/src/scanning/scanningOptions/ScanningNewProfileScreen/ScanningNewProfileScreen.jsx b/src/scanning/scanningOptions/screens/ScanningNewProfileScreen/ScanningNewProfileScreen.jsx similarity index 85% rename from src/scanning/scanningOptions/ScanningNewProfileScreen/ScanningNewProfileScreen.jsx rename to src/scanning/scanningOptions/screens/ScanningNewProfileScreen/ScanningNewProfileScreen.jsx index 1b1ff56..3c8c01c 100644 --- a/src/scanning/scanningOptions/ScanningNewProfileScreen/ScanningNewProfileScreen.jsx +++ b/src/scanning/scanningOptions/screens/ScanningNewProfileScreen/ScanningNewProfileScreen.jsx @@ -7,7 +7,7 @@ import { IonTitle, IonToolbar, } from "@ionic/react"; -import { ScanningProfileCreator } from "../ScanningProfileCreator/ScanningProfileCreator.jsx"; +import { ScanningProfileCreator } from "../../components/ScanningProfileCreator/ScanningProfileCreator.jsx"; import { useHistory } from "react-router"; export const ScanningNewProfileScreen = () => { diff --git a/src/scanning/scanningOptions/ScanningOptionsScreen/ScanningOptionsScreen.jsx b/src/scanning/scanningOptions/screens/ScanningOptionsScreen/ScanningOptionsScreen.jsx similarity index 90% rename from src/scanning/scanningOptions/ScanningOptionsScreen/ScanningOptionsScreen.jsx rename to src/scanning/scanningOptions/screens/ScanningOptionsScreen/ScanningOptionsScreen.jsx index 0934619..a8b0bc0 100644 --- a/src/scanning/scanningOptions/ScanningOptionsScreen/ScanningOptionsScreen.jsx +++ b/src/scanning/scanningOptions/screens/ScanningOptionsScreen/ScanningOptionsScreen.jsx @@ -9,7 +9,7 @@ import { IonTitle, IonToolbar, } from "@ionic/react"; -import { ScanningOptionsForm } from "../ScanningOptionsForm/ScanningOptionsForm.jsx"; +import { ScanningOptionsForm } from "../../components/ScanningOptionsForm/ScanningOptionsForm.jsx"; import React, { Suspense } from "react"; export const ScanningOptionsScreen = () => { diff --git a/src/scanning/scanningOptions/ScanningOptionsScreen/ScanningOptionsScreen.scss b/src/scanning/scanningOptions/screens/ScanningOptionsScreen/ScanningOptionsScreen.scss similarity index 100% rename from src/scanning/scanningOptions/ScanningOptionsScreen/ScanningOptionsScreen.scss rename to src/scanning/scanningOptions/screens/ScanningOptionsScreen/ScanningOptionsScreen.scss diff --git a/src/scanning/scanningOptions/ScanningProfiles/ScanningProfiles.jsx b/src/scanning/scanningOptions/screens/ScanningProfilesScreen/ScanningProfilesScreen.jsx similarity index 78% rename from src/scanning/scanningOptions/ScanningProfiles/ScanningProfiles.jsx rename to src/scanning/scanningOptions/screens/ScanningProfilesScreen/ScanningProfilesScreen.jsx index 7e4a2b3..b1b6521 100644 --- a/src/scanning/scanningOptions/ScanningProfiles/ScanningProfiles.jsx +++ b/src/scanning/scanningOptions/screens/ScanningProfilesScreen/ScanningProfilesScreen.jsx @@ -9,15 +9,15 @@ import { IonTitle, IonToolbar, } from "@ionic/react"; -import { useUserAccessibleGroups } from "../../../common/hooks.js"; -import { UserContext } from "../../../common/context.js"; +import { useUserAccessibleGroups } from "../../../../common/common.hooks.js"; +import { UserContext } from "../../../../common/common.context.js"; import { useCallback, useContext } from "react"; -import { useScanningProfiles } from "../../scanningHooks.js"; -import { ProfileListItem } from "../ProfileListItem/ProfileListItem.jsx"; +import { useScanningProfiles } from "../../../scanning.hooks.js"; +import { ProfileListItem } from "../../components/ProfileListItem/ProfileListItem.jsx"; import { useHistory } from "react-router"; -import { navigateWithParams } from "../../../common/util.js"; +import { navigateWithParams } from "../../../../common/common.lib.js"; -export const ScanningProfiles = () => { +export const ScanningProfilesScreen = () => { const history = useHistory(); const { userInfo } = useContext(UserContext); const { profiles } = useScanningProfiles(userInfo); @@ -26,7 +26,7 @@ export const ScanningProfiles = () => { const handleOnProfileClick = useCallback( /** - * @param {import("../../../onboarding/auth").ScanningProfile} profile + * @param {import("../../../../onboarding/onboarding.lib.js").ScanningProfile} profile */ (profile) => { navigateWithParams(history, "/scanning", { diff --git a/src/scanning/scanningSession/CandidateList/CandidateListScreen.scss b/src/scanning/scanningSession/CandidateList/CandidateListScreen.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/scanning/scanningSession/CandidateAnnotationItem/CandidateAnnotationItem.jsx b/src/scanning/scanningSession/components/CandidateAnnotationItem/CandidateAnnotationItem.jsx similarity index 81% rename from src/scanning/scanningSession/CandidateAnnotationItem/CandidateAnnotationItem.jsx rename to src/scanning/scanningSession/components/CandidateAnnotationItem/CandidateAnnotationItem.jsx index b1a293c..8ed2354 100644 --- a/src/scanning/scanningSession/CandidateAnnotationItem/CandidateAnnotationItem.jsx +++ b/src/scanning/scanningSession/components/CandidateAnnotationItem/CandidateAnnotationItem.jsx @@ -1,18 +1,11 @@ import "./CandidateAnnotationItem.scss"; -import { - IonIcon, - IonItem, - IonLabel, - IonList, - IonListHeader, - IonText, -} from "@ionic/react"; -import { useCopyAnnotationLineOnClick } from "../../scanningLib.js"; +import { IonIcon, IonItem, IonLabel, IonList, IonListHeader, IonText } from "@ionic/react"; +import { useCopyAnnotationLineOnClick } from "../../../scanning.lib.js"; import { copyOutline } from "ionicons/icons"; /** * @param {Object} props - * @param {import("../../scanningLib.js").CandidateAnnotation} props.annotation + * @param {import("../../../scanning.lib.js").CandidateAnnotation} props.annotation * @returns {JSX.Element} */ export const CandidateAnnotationItem = ({ annotation }) => { diff --git a/src/scanning/scanningSession/CandidateAnnotationItem/CandidateAnnotationItem.scss b/src/scanning/scanningSession/components/CandidateAnnotationItem/CandidateAnnotationItem.scss similarity index 100% rename from src/scanning/scanningSession/CandidateAnnotationItem/CandidateAnnotationItem.scss rename to src/scanning/scanningSession/components/CandidateAnnotationItem/CandidateAnnotationItem.scss diff --git a/src/scanning/scanningSession/CandidateAnnotations/CandidateAnnotations.jsx b/src/scanning/scanningSession/components/CandidateAnnotations/CandidateAnnotations.jsx similarity index 87% rename from src/scanning/scanningSession/CandidateAnnotations/CandidateAnnotations.jsx rename to src/scanning/scanningSession/components/CandidateAnnotations/CandidateAnnotations.jsx index fac4c07..cb40e37 100644 --- a/src/scanning/scanningSession/CandidateAnnotations/CandidateAnnotations.jsx +++ b/src/scanning/scanningSession/components/CandidateAnnotations/CandidateAnnotations.jsx @@ -3,7 +3,7 @@ import { CandidateAnnotationItem } from "../CandidateAnnotationItem/CandidateAnn /** * @param {Object} props - * @param {import("../../scanningLib.js").Candidate} props.candidate + * @param {import("../../../scanning.lib.js").Candidate} props.candidate * @returns {JSX.Element} */ export const CandidateAnnotations = ({ candidate }) => { diff --git a/src/scanning/scanningSession/CandidateAnnotations/CandidateAnnotations.scss b/src/scanning/scanningSession/components/CandidateAnnotations/CandidateAnnotations.scss similarity index 100% rename from src/scanning/scanningSession/CandidateAnnotations/CandidateAnnotations.scss rename to src/scanning/scanningSession/components/CandidateAnnotations/CandidateAnnotations.scss diff --git a/src/scanning/scanningSession/CandidateAnnotationsViewer/CandidateAnnotationsViewer.jsx b/src/scanning/scanningSession/components/CandidateAnnotationsViewer/CandidateAnnotationsViewer.jsx similarity index 85% rename from src/scanning/scanningSession/CandidateAnnotationsViewer/CandidateAnnotationsViewer.jsx rename to src/scanning/scanningSession/components/CandidateAnnotationsViewer/CandidateAnnotationsViewer.jsx index 4cb2b12..194f626 100644 --- a/src/scanning/scanningSession/CandidateAnnotationsViewer/CandidateAnnotationsViewer.jsx +++ b/src/scanning/scanningSession/components/CandidateAnnotationsViewer/CandidateAnnotationsViewer.jsx @@ -3,7 +3,7 @@ import { CandidateAnnotations } from "../CandidateAnnotations/CandidateAnnotatio /** * @param {Object} props - * @param {import("../../scanningLib.js").Candidate} props.candidate + * @param {import("../../../scanning.lib.js").Candidate} props.candidate * @returns {JSX.Element} */ export const CandidateAnnotationsViewer = ({ candidate }) => { diff --git a/src/scanning/scanningSession/CandidatePhotometryChart/CandidatePhotometryChart.jsx b/src/scanning/scanningSession/components/CandidatePhotometryChart/CandidatePhotometryChart.jsx similarity index 91% rename from src/scanning/scanningSession/CandidatePhotometryChart/CandidatePhotometryChart.jsx rename to src/scanning/scanningSession/components/CandidatePhotometryChart/CandidatePhotometryChart.jsx index 170fbb7..b6dbbfe 100644 --- a/src/scanning/scanningSession/CandidatePhotometryChart/CandidatePhotometryChart.jsx +++ b/src/scanning/scanningSession/components/CandidatePhotometryChart/CandidatePhotometryChart.jsx @@ -1,12 +1,12 @@ import "./CandidatePhotometryChart.scss"; import { memo, useContext, useEffect, useRef, useState } from "react"; import embed from "vega-embed"; -import { getVegaPlotSpec } from "../../scanningLib.js"; -import { useBandpassesColors } from "../../../common/hooks.js"; +import { getVegaPlotSpec } from "../../../scanning.lib.js"; +import { useBandpassesColors } from "../../../../common/common.hooks.js"; import { IonSkeletonText } from "@ionic/react"; -import { fetchSourcePhotometry } from "../../scanningRequests.js"; +import { fetchSourcePhotometry } from "../../../scanning.requests.js"; import { useMutation } from "@tanstack/react-query"; -import { UserContext } from "../../../common/context.js"; +import { UserContext } from "../../../../common/common.context.js"; /** * @param {Object} props diff --git a/src/scanning/scanningSession/CandidatePhotometryChart/CandidatePhotometryChart.scss b/src/scanning/scanningSession/components/CandidatePhotometryChart/CandidatePhotometryChart.scss similarity index 100% rename from src/scanning/scanningSession/CandidatePhotometryChart/CandidatePhotometryChart.scss rename to src/scanning/scanningSession/components/CandidatePhotometryChart/CandidatePhotometryChart.scss diff --git a/src/scanning/scanningSession/CandidateScanner/CandidateScanner.jsx b/src/scanning/scanningSession/components/CandidateScanner/CandidateScanner.jsx similarity index 92% rename from src/scanning/scanningSession/CandidateScanner/CandidateScanner.jsx rename to src/scanning/scanningSession/components/CandidateScanner/CandidateScanner.jsx index 775864c..7e614f4 100644 --- a/src/scanning/scanningSession/CandidateScanner/CandidateScanner.jsx +++ b/src/scanning/scanningSession/components/CandidateScanner/CandidateScanner.jsx @@ -1,21 +1,24 @@ import "./CandidateScanner.scss"; import { IonModal, useIonAlert, useIonToast } from "@ionic/react"; import { useCallback, useContext, useEffect, useRef, useState } from "react"; -import { useUserAccessibleGroups } from "../../../common/hooks.js"; +import { useUserAccessibleGroups } from "../../../../common/common.hooks.js"; import { checkmarkCircleOutline, warningOutline } from "ionicons/icons"; import useEmblaCarousel from "embla-carousel-react"; import { CandidateAnnotationsViewer } from "../CandidateAnnotationsViewer/CandidateAnnotationsViewer.jsx"; import { ScanningCard } from "../ScanningCard/ScanningCard.jsx"; import { ScanningCardSkeleton } from "../ScanningCard/ScanningCardSkeleton.jsx"; -import { useSearchCandidates } from "../../scanningHooks.js"; -import { addSourceToGroups } from "../../scanningRequests.js"; +import { useSearchCandidates } from "../../../scanning.hooks.js"; +import { addSourceToGroups } from "../../../scanning.requests.js"; import { useMutation } from "@tanstack/react-query"; -import { parseIntList, SCANNING_TOOLBAR_ACTION } from "../../scanningLib.js"; +import { + parseIntList, + SCANNING_TOOLBAR_ACTION, +} from "../../../scanning.lib.js"; import { ScanningEnd } from "../ScanningEnd/ScanningEnd.jsx"; import { ScanningToolbar } from "../ScanningToolbar/ScanningToolbar.jsx"; import { useLocation } from "react-router"; -import { CANDIDATES_PER_PAGE } from "../../../common/constants.js"; -import { UserContext } from "../../../common/context.js"; +import { UserContext } from "../../../../common/common.context.js"; +import { CANDIDATES_PER_PAGE } from "../../../../common/common.lib.js"; export const CandidateScanner = () => { const { userInfo } = useContext(UserContext); @@ -24,12 +27,12 @@ export const CandidateScanner = () => { /** @type {{state: any}} */ const { state } = useLocation(); - /** @type {import("../../scanningLib.js").ScanningConfig|undefined} */ + /** @type {import("../../../scanning.lib.js").ScanningConfig|undefined} */ let scanningConfig = undefined; if (state) { scanningConfig = { ...state, - /** @type {import("../../scanningLib").Group[]} **/ + /** @type {import("../../../scanning.lib.js").Group[]} **/ saveGroups: userAccessibleGroups ? state.saveGroupIds .map((/** @type {number} */ id) => @@ -37,11 +40,11 @@ export const CandidateScanner = () => { ) .filter( ( - /** @type {import("../../scanningLib.js").Group | undefined} */ g, + /** @type {import("../../../scanning.lib.js").Group | undefined} */ g, ) => g !== undefined, ) : [], - /** @type {import("../../scanningLib").Group[]} **/ + /** @type {import("../../../scanning.lib.js").Group[]} **/ // @ts-ignore junkGroups: userAccessibleGroups ? parseIntList(state.junkGroupIDs) @@ -65,7 +68,7 @@ export const CandidateScanner = () => { const [isLastBatch, setIsLastBatch] = useState(false); - /** @type {React.MutableRefObject} */ + /** @type {React.MutableRefObject} */ // @ts-ignore const scanningRecap = useRef({ queryId: "", @@ -75,7 +78,7 @@ export const CandidateScanner = () => { }); const { data, fetchNextPage, isFetchingNextPage } = useSearchCandidates(); const totalMatches = data?.pages[0].totalMatches; - /** @type {import("../../scanningLib.js").Candidate[]|undefined} */ + /** @type {import("../../../scanning.lib.js").Candidate[]|undefined} */ const candidates = data?.pages.map((page) => page.candidates).flat(1); const currentCandidate = candidates?.at(currentIndex); @@ -326,7 +329,7 @@ export const CandidateScanner = () => { }; /** - * @param {import("../../scanningLib.js").ScanningToolbarAction} action + * @param {import("../../../scanning.lib.js").ScanningToolbarAction} action */ const handleToolbarAction = async (action) => { switch (action) { diff --git a/src/scanning/scanningSession/CandidateScanner/CandidateScanner.scss b/src/scanning/scanningSession/components/CandidateScanner/CandidateScanner.scss similarity index 100% rename from src/scanning/scanningSession/CandidateScanner/CandidateScanner.scss rename to src/scanning/scanningSession/components/CandidateScanner/CandidateScanner.scss diff --git a/src/scanning/scanningSession/PinnedAnnotations/PinnedAnnotations.jsx b/src/scanning/scanningSession/components/PinnedAnnotations/PinnedAnnotations.jsx similarity index 94% rename from src/scanning/scanningSession/PinnedAnnotations/PinnedAnnotations.jsx rename to src/scanning/scanningSession/components/PinnedAnnotations/PinnedAnnotations.jsx index cd6190b..84ee82b 100644 --- a/src/scanning/scanningSession/PinnedAnnotations/PinnedAnnotations.jsx +++ b/src/scanning/scanningSession/components/PinnedAnnotations/PinnedAnnotations.jsx @@ -1,16 +1,12 @@ import "./PinnedAnnotations.scss"; import { IonButton, IonIcon, IonItem, IonText } from "@ionic/react"; -import { - extractAnnotationOriginAndKey, - getAnnotationId, - useCopyAnnotationLineOnClick, -} from "../../scanningLib.js"; +import { extractAnnotationOriginAndKey, getAnnotationId, useCopyAnnotationLineOnClick } from "../../../scanning.lib.js"; import { copyOutline } from "ionicons/icons"; import { useState } from "react"; /** * @param {Object} props - * @param {import("../../scanningLib.js").Candidate} props.candidate + * @param {import("../../../scanning.lib.js").Candidate} props.candidate * @param {() => void} props.onButtonClick * @param {string[]} [props.pinnedAnnotationIds] * @returns {JSX.Element} diff --git a/src/scanning/scanningSession/PinnedAnnotations/PinnedAnnotations.scss b/src/scanning/scanningSession/components/PinnedAnnotations/PinnedAnnotations.scss similarity index 100% rename from src/scanning/scanningSession/PinnedAnnotations/PinnedAnnotations.scss rename to src/scanning/scanningSession/components/PinnedAnnotations/PinnedAnnotations.scss diff --git a/src/scanning/scanningSession/PinnedAnnotationsSkeleton/PinnedAnnotationsSkeleton.jsx b/src/scanning/scanningSession/components/PinnedAnnotationsSkeleton/PinnedAnnotationsSkeleton.jsx similarity index 100% rename from src/scanning/scanningSession/PinnedAnnotationsSkeleton/PinnedAnnotationsSkeleton.jsx rename to src/scanning/scanningSession/components/PinnedAnnotationsSkeleton/PinnedAnnotationsSkeleton.jsx diff --git a/src/scanning/scanningSession/ScanningCard/ScanningCard.jsx b/src/scanning/scanningSession/components/ScanningCard/ScanningCard.jsx similarity index 93% rename from src/scanning/scanningSession/ScanningCard/ScanningCard.jsx rename to src/scanning/scanningSession/components/ScanningCard/ScanningCard.jsx index 0fed1a9..6d5c1c4 100644 --- a/src/scanning/scanningSession/ScanningCard/ScanningCard.jsx +++ b/src/scanning/scanningSession/components/ScanningCard/ScanningCard.jsx @@ -1,5 +1,5 @@ import "./ScanningCard.scss"; -import { THUMBNAIL_TYPES } from "../../scanningLib.js"; +import { THUMBNAIL_TYPES } from "../../../scanning.lib.js"; import { Thumbnail } from "../Thumbnail/Thumbnail.jsx"; import { PinnedAnnotations } from "../PinnedAnnotations/PinnedAnnotations.jsx"; import { CandidatePhotometryChart } from "../CandidatePhotometryChart/CandidatePhotometryChart.jsx"; @@ -9,7 +9,7 @@ import { ScanningCardSkeleton } from "./ScanningCardSkeleton.jsx"; /** * Scanning card component * @param {Object} props - * @param {import("../../scanningLib.js").Candidate} props.candidate + * @param {import("../../../scanning.lib.js").Candidate} props.candidate * @param {React.MutableRefObject} props.modal * @param {number} props.currentIndex * @param {number} props.nbCandidates diff --git a/src/scanning/scanningSession/ScanningCard/ScanningCard.scss b/src/scanning/scanningSession/components/ScanningCard/ScanningCard.scss similarity index 100% rename from src/scanning/scanningSession/ScanningCard/ScanningCard.scss rename to src/scanning/scanningSession/components/ScanningCard/ScanningCard.scss diff --git a/src/scanning/scanningSession/ScanningCard/ScanningCardSkeleton.jsx b/src/scanning/scanningSession/components/ScanningCard/ScanningCardSkeleton.jsx similarity index 90% rename from src/scanning/scanningSession/ScanningCard/ScanningCardSkeleton.jsx rename to src/scanning/scanningSession/components/ScanningCard/ScanningCardSkeleton.jsx index a8c329b..67d6048 100644 --- a/src/scanning/scanningSession/ScanningCard/ScanningCardSkeleton.jsx +++ b/src/scanning/scanningSession/components/ScanningCard/ScanningCardSkeleton.jsx @@ -1,7 +1,7 @@ import "./ScanningCard.scss"; import { IonSkeletonText } from "@ionic/react"; -import { THUMBNAIL_TYPES } from "../../scanningLib.js"; -import { ThumbnailSkeleton } from "../ThumnailSkeleton/ThumbnailSkeleton.jsx"; +import { THUMBNAIL_TYPES } from "../../../scanning.lib.js"; +import { ThumbnailSkeleton } from "../Thumbnail/ThumbnailSkeleton.jsx"; import { PinnedAnnotationsSkeleton } from "../PinnedAnnotationsSkeleton/PinnedAnnotationsSkeleton.jsx"; /** diff --git a/src/scanning/scanningSession/ScanningEnd/ScanningEnd.jsx b/src/scanning/scanningSession/components/ScanningEnd/ScanningEnd.jsx similarity index 86% rename from src/scanning/scanningSession/ScanningEnd/ScanningEnd.jsx rename to src/scanning/scanningSession/components/ScanningEnd/ScanningEnd.jsx index 2694129..1e92f27 100644 --- a/src/scanning/scanningSession/ScanningEnd/ScanningEnd.jsx +++ b/src/scanning/scanningSession/components/ScanningEnd/ScanningEnd.jsx @@ -4,7 +4,7 @@ import { useHistory } from "react-router"; /** * @param {Object} props - * @param {React.MutableRefObject} props.recap + * @param {React.MutableRefObject} props.recap * @returns {JSX.Element} */ export const ScanningEnd = ({ recap }) => { diff --git a/src/scanning/scanningSession/ScanningEnd/ScanningEnd.scss b/src/scanning/scanningSession/components/ScanningEnd/ScanningEnd.scss similarity index 100% rename from src/scanning/scanningSession/ScanningEnd/ScanningEnd.scss rename to src/scanning/scanningSession/components/ScanningEnd/ScanningEnd.scss diff --git a/src/scanning/scanningSession/ScanningToolbar/ScanningToolbar.jsx b/src/scanning/scanningSession/components/ScanningToolbar/ScanningToolbar.jsx similarity index 91% rename from src/scanning/scanningSession/ScanningToolbar/ScanningToolbar.jsx rename to src/scanning/scanningSession/components/ScanningToolbar/ScanningToolbar.jsx index 7173e4e..7ba38fc 100644 --- a/src/scanning/scanningSession/ScanningToolbar/ScanningToolbar.jsx +++ b/src/scanning/scanningSession/components/ScanningToolbar/ScanningToolbar.jsx @@ -1,13 +1,5 @@ import "./ScanningToolbar.scss"; -import { - IonButton, - IonContent, - IonIcon, - IonItem, - IonLabel, - IonList, - useIonPopover, -} from "@ionic/react"; +import { IonButton, IonContent, IonIcon, IonItem, IonLabel, IonList, useIonPopover } from "@ionic/react"; import { bookmarkOutline, ellipsisHorizontal, @@ -16,14 +8,14 @@ import { locateOutline, planetOutline, telescopeOutline, - trashBinOutline, + trashBinOutline } from "ionicons/icons"; -import { SCANNING_TOOLBAR_ACTION } from "../../scanningLib.js"; +import { SCANNING_TOOLBAR_ACTION } from "../../../scanning.lib.js"; import { useState } from "react"; /** * @param {Object} props - * @param {(action: import("../../scanningLib").ScanningToolbarAction) => void} props.onAction + * @param {(action: import("../../../scanning.lib.js").ScanningToolbarAction) => void} props.onAction * @param {boolean} props.isDiscardingEnabled * @returns {JSX.Element} */ diff --git a/src/scanning/scanningSession/ScanningToolbar/ScanningToolbar.scss b/src/scanning/scanningSession/components/ScanningToolbar/ScanningToolbar.scss similarity index 100% rename from src/scanning/scanningSession/ScanningToolbar/ScanningToolbar.scss rename to src/scanning/scanningSession/components/ScanningToolbar/ScanningToolbar.scss diff --git a/src/scanning/scanningSession/Thumbnail/Thumbnail.jsx b/src/scanning/scanningSession/components/Thumbnail/Thumbnail.jsx similarity index 86% rename from src/scanning/scanningSession/Thumbnail/Thumbnail.jsx rename to src/scanning/scanningSession/components/Thumbnail/Thumbnail.jsx index 9026e38..9a42348 100644 --- a/src/scanning/scanningSession/Thumbnail/Thumbnail.jsx +++ b/src/scanning/scanningSession/components/Thumbnail/Thumbnail.jsx @@ -1,15 +1,11 @@ import "./Thumbnail.scss"; -import { - getThumbnailAltAndSurveyLink, - getThumbnailHeader, - getThumbnailImageUrl, -} from "../../scanningLib.js"; +import { getThumbnailAltAndSurveyLink, getThumbnailHeader, getThumbnailImageUrl } from "../../../scanning.lib.js"; import { useState } from "react"; /** * Thumbnail component * @param {Object} props - * @param {import("../../scanningLib.js").Candidate} props.candidate + * @param {import("../../../scanning.lib.js").Candidate} props.candidate * @param {string} props.type */ export const Thumbnail = ({ candidate, type }) => { diff --git a/src/scanning/scanningSession/Thumbnail/Thumbnail.scss b/src/scanning/scanningSession/components/Thumbnail/Thumbnail.scss similarity index 100% rename from src/scanning/scanningSession/Thumbnail/Thumbnail.scss rename to src/scanning/scanningSession/components/Thumbnail/Thumbnail.scss diff --git a/src/scanning/scanningSession/ThumnailSkeleton/ThumbnailSkeleton.jsx b/src/scanning/scanningSession/components/Thumbnail/ThumbnailSkeleton.jsx similarity index 90% rename from src/scanning/scanningSession/ThumnailSkeleton/ThumbnailSkeleton.jsx rename to src/scanning/scanningSession/components/Thumbnail/ThumbnailSkeleton.jsx index f25469d..a2b0c8f 100644 --- a/src/scanning/scanningSession/ThumnailSkeleton/ThumbnailSkeleton.jsx +++ b/src/scanning/scanningSession/components/Thumbnail/ThumbnailSkeleton.jsx @@ -1,6 +1,6 @@ import "../Thumbnail/Thumbnail.scss"; import { IonSkeletonText } from "@ionic/react"; -import { getThumbnailHeader } from "../../scanningLib.js"; +import { getThumbnailHeader } from "../../../scanning.lib.js"; /** * @param {Object} props diff --git a/src/scanning/scanningSession/CandidateList/CandidateListScreen.jsx b/src/scanning/scanningSession/screens/CandidateListScreen/CandidateListScreen.jsx similarity index 100% rename from src/scanning/scanningSession/CandidateList/CandidateListScreen.jsx rename to src/scanning/scanningSession/screens/CandidateListScreen/CandidateListScreen.jsx diff --git a/src/scanning/scanningSession/MainScanningScreen/MainScanningScreen.jsx b/src/scanning/scanningSession/screens/MainScanningScreen/MainScanningScreen.jsx similarity index 89% rename from src/scanning/scanningSession/MainScanningScreen/MainScanningScreen.jsx rename to src/scanning/scanningSession/screens/MainScanningScreen/MainScanningScreen.jsx index f20728b..a9f5104 100644 --- a/src/scanning/scanningSession/MainScanningScreen/MainScanningScreen.jsx +++ b/src/scanning/scanningSession/screens/MainScanningScreen/MainScanningScreen.jsx @@ -1,6 +1,6 @@ import "./MainScanningScreen.scss"; import { IonContent, IonPage, IonSpinner } from "@ionic/react"; -import { CandidateScanner } from "../CandidateScanner/CandidateScanner.jsx"; +import { CandidateScanner } from "../../components/CandidateScanner/CandidateScanner.jsx"; import React, { Suspense } from "react"; export const MainScanningScreen = () => { diff --git a/src/scanning/scanningSession/MainScanningScreen/MainScanningScreen.scss b/src/scanning/scanningSession/screens/MainScanningScreen/MainScanningScreen.scss similarity index 100% rename from src/scanning/scanningSession/MainScanningScreen/MainScanningScreen.scss rename to src/scanning/scanningSession/screens/MainScanningScreen/MainScanningScreen.scss diff --git a/src/scanning/scanningSession/ScanningRecap/ScanningRecap.jsx b/src/scanning/scanningSession/screens/ScanningRecapScreen/ScanningRecapScreen.jsx similarity index 91% rename from src/scanning/scanningSession/ScanningRecap/ScanningRecap.jsx rename to src/scanning/scanningSession/screens/ScanningRecapScreen/ScanningRecapScreen.jsx index 6d08acc..520b086 100644 --- a/src/scanning/scanningSession/ScanningRecap/ScanningRecap.jsx +++ b/src/scanning/scanningSession/screens/ScanningRecapScreen/ScanningRecapScreen.jsx @@ -1,4 +1,4 @@ -import "./ScanningRecap.scss"; +import "./ScanningRecapScreen.scss"; import { IonButton, IonContent, @@ -15,21 +15,21 @@ import moment from "moment-timezone"; import { useCallback, useContext } from "react"; import { useHistory, useLocation } from "react-router"; import { exitOutline, linkOutline, mailOutline } from "ionicons/icons"; -import { UserContext } from "../../../common/context.js"; +import { UserContext } from "../../../../common/common.context.js"; -export const ScanningRecap = () => { +export const ScanningRecapScreen = () => { const { userInfo } = useContext(UserContext); const location = useLocation(); const history = useHistory(); /** - * @type {import("../../scanningLib").ScanningRecap|undefined} + * @type {import("../../../scanning.lib.js").ScanningRecap|undefined} */ // @ts-ignore const recap = location.state?.recap; const getLink = useCallback( /** - * @param {import("../../scanningLib").Candidate} source + * @param {import("../../../scanning.lib.js").Candidate} source * @returns {string} */ (source) => { diff --git a/src/scanning/scanningSession/ScanningRecap/ScanningRecap.scss b/src/scanning/scanningSession/screens/ScanningRecapScreen/ScanningRecapScreen.scss similarity index 100% rename from src/scanning/scanningSession/ScanningRecap/ScanningRecap.scss rename to src/scanning/scanningSession/screens/ScanningRecapScreen/ScanningRecapScreen.scss diff --git a/src/sources/SourceList/SourceList.jsx b/src/sources/components/SourceList/SourceList.jsx similarity index 88% rename from src/sources/SourceList/SourceList.jsx rename to src/sources/components/SourceList/SourceList.jsx index 6372277..c6b5d81 100644 --- a/src/sources/SourceList/SourceList.jsx +++ b/src/sources/components/SourceList/SourceList.jsx @@ -1,7 +1,7 @@ import "./SourceList.scss"; import { SourceListItem } from "../SourceListItem/SourceListItem.jsx"; import { useState } from "react"; -import { useFetchSources } from "../../common/hooks.js"; +import { useFetchSources } from "../../../common/common.hooks.js"; export const SourceList = () => { const [page, setPage] = useState(1); diff --git a/src/sources/SourceList/SourceList.scss b/src/sources/components/SourceList/SourceList.scss similarity index 100% rename from src/sources/SourceList/SourceList.scss rename to src/sources/components/SourceList/SourceList.scss diff --git a/src/sources/SourceListItem/SourceListItem.jsx b/src/sources/components/SourceListItem/SourceListItem.jsx similarity index 85% rename from src/sources/SourceListItem/SourceListItem.jsx rename to src/sources/components/SourceListItem/SourceListItem.jsx index a401c92..e0ceda7 100644 --- a/src/sources/SourceListItem/SourceListItem.jsx +++ b/src/sources/components/SourceListItem/SourceListItem.jsx @@ -4,7 +4,7 @@ import { starOutline } from "ionicons/icons"; /** * @param {Object} props - * @param {import("../sources").Source} props.source + * @param {import("../../sources.lib.js").Source} props.source * @returns {JSX.Element} */ export const SourceListItem = ({ source }) => { @@ -18,7 +18,7 @@ export const SourceListItem = ({ source }) => {
-
Created:
+
Created:
{new Date(source.created_at).toLocaleString("en-US", { day: "numeric", @@ -32,11 +32,11 @@ export const SourceListItem = ({ source }) => {
-
RA:
+
RA:
{source.ra}
-
DEC:
+
DEC:
{source.dec}
diff --git a/src/sources/SourceListItem/SourceListItem.scss b/src/sources/components/SourceListItem/SourceListItem.scss similarity index 100% rename from src/sources/SourceListItem/SourceListItem.scss rename to src/sources/components/SourceListItem/SourceListItem.scss diff --git a/src/sources/SourceListScreen/SourceListScreen.jsx b/src/sources/screens/SourceListTab/SourceListTab.jsx similarity index 73% rename from src/sources/SourceListScreen/SourceListScreen.jsx rename to src/sources/screens/SourceListTab/SourceListTab.jsx index 69dd590..f90ac44 100644 --- a/src/sources/SourceListScreen/SourceListScreen.jsx +++ b/src/sources/screens/SourceListTab/SourceListTab.jsx @@ -1,9 +1,9 @@ -import "./SourceListScreen.scss"; +import "./SourceListTab.scss"; import { IonContent, IonHeader, IonTitle, IonToolbar } from "@ionic/react"; import { Suspense } from "react"; -import { SourceList } from "../SourceList/SourceList.jsx"; +import { SourceList } from "../../components/SourceList/SourceList.jsx"; -export const SourceListScreen = () => { +export const SourceListTab = () => { return ( <> diff --git a/src/sources/SourceListScreen/SourceListScreen.scss b/src/sources/screens/SourceListTab/SourceListTab.scss similarity index 100% rename from src/sources/SourceListScreen/SourceListScreen.scss rename to src/sources/screens/SourceListTab/SourceListTab.scss diff --git a/src/sources/sources.js b/src/sources/sources.lib.js similarity index 86% rename from src/sources/sources.js rename to src/sources/sources.lib.js index 6f625e6..cd76c81 100644 --- a/src/sources/sources.js +++ b/src/sources/sources.lib.js @@ -12,10 +12,10 @@ import { CapacitorHttp } from "@capacitor/core"; /** * Fetch sources from the API * @param {Object} props - * @param {import("../onboarding/auth.js").UserInfo} props.userInfo - User info + * @param {import("../onboarding/onboarding.lib.js").UserInfo} props.userInfo - User info * @param {number} props.page - page number * @param {number} props.numPerPage - number of sources per page - * @returns {Promise} + * @returns {Promise} */ export async function fetchSources({ userInfo, page, numPerPage }) { let response = await CapacitorHttp.get({ diff --git a/src/theme/variables.scss b/src/theme/variables.scss index 13f9117..b3c091d 100644 --- a/src/theme/variables.scss +++ b/src/theme/variables.scss @@ -1,27 +1,5 @@ /* For information on how to create your own theme, please see: http://ionicframework.com/docs/theming/ */ -@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"); - -h1, -h2, -h3, -h4, -h5, -h6, -p, -ion-skeleton-text { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -.app-loading { - display: flex; - justify-content: center; - align-items: center; - height: 100vh; - background-color: var(--ion-background-color); -} :root { --ion-color-primary: #195676; @@ -143,79 +121,4 @@ ion-skeleton-text { --ion-color-light-shade: #0f1213; --ion-color-light-tint: #292c2d; - //--ion-color-medium: #5f5f5f; - //--ion-color-medium-rgb: 95, 95, 95; - //--ion-color-medium-contrast: #ffffff; - //--ion-color-medium-contrast-rgb: 255, 255, 255; - //--ion-color-medium-shade: #545454; - //--ion-color-medium-tint: #6f6f6f; - // - //--ion-color-dark: #2f2f2f; - //--ion-color-dark-rgb: 47, 47, 47; - //--ion-color-dark-contrast: #ffffff; - //--ion-color-dark-contrast-rgb: 255, 255, 255; - //--ion-color-dark-shade: #292929; - //--ion-color-dark-tint: #444444; - - //--ion-background-color: #2f2f2f; -} - -form { - .form-section { - margin-bottom: 1rem; - } - - .form-list-header { - padding-left: 2rem; - font-size: 0.7rem; - text-transform: uppercase; - color: var(--ion-color-secondary); - } - - ion-list.list-ios.list-inset { - margin-top: 1.7rem; - margin-bottom: 0.5rem; - } - - .form-list-header + ion-list.list-ios.list-inset { - margin-top: 0.2rem; - } - - ion-list { - background: var(--ion-color-light); - - ion-item { - --background: var(--ion-color-light); - } - - ion-list-header { - font-size: 0.8rem; - font-weight: 800; - - ion-label { - margin-top: 0; - } - } - } - - .error-container { - height: fit-content; - margin: 0.1rem 0; - } -} - -.form-footer { - padding: 0.5rem 1rem var(--ion-safe-area-bottom); - z-index: 2; - width: 100%; - height: auto; - box-shadow: 1px -1px 5px 0 rgba(var(--ion-color-medium-rgb), 0.25); - background: var(--ion-color-light); - - ion-button { - --padding-start: 4rem; - --padding-end: 4rem; - --padding-top: 1rem; - --padding-bottom: 1rem; - } } diff --git a/src/userProfile/UserProfileScreen/UserProfileScreen.jsx b/src/userProfile/screens/UserProfileScreen/UserProfileTab.jsx similarity index 91% rename from src/userProfile/UserProfileScreen/UserProfileScreen.jsx rename to src/userProfile/screens/UserProfileScreen/UserProfileTab.jsx index 3e773a6..c26af33 100644 --- a/src/userProfile/UserProfileScreen/UserProfileScreen.jsx +++ b/src/userProfile/screens/UserProfileScreen/UserProfileTab.jsx @@ -14,16 +14,19 @@ import { IonToolbar, useIonAlert, } from "@ionic/react"; -import { useUserProfile } from "../../common/hooks.js"; +import { useUserProfile } from "../../../common/common.hooks.js"; import { useContext } from "react"; -import { AppContext, UserContext } from "../../common/context.js"; +import { AppContext, UserContext } from "../../../common/common.context.js"; import { swapHorizontal } from "ionicons/icons"; import { useMutation } from "@tanstack/react-query"; -import { clearPreference, setPreference } from "../../common/preferences.js"; -import { QUERY_KEYS } from "../../common/constants.js"; -import { setDarkModeInDocument } from "../../common/util.js"; +import { + clearPreference, + QUERY_KEYS, + setDarkModeInDocument, + setPreference, +} from "../../../common/common.lib.js"; -export const UserProfileScreen = () => { +export const UserProfileTab = () => { const { darkMode, updateDarkMode } = useContext(AppContext); const { userInfo, updateUserInfo } = useContext(UserContext); const [presentAlert] = useIonAlert();