- login as an admin in an organization.
- create slots
- slots have the following properties:
- multiple intervals
- type: on or off-ice
- categories: competitive level of athletes for a given slot (can contain multiple aptitute levels)
- mark athletes as present or absent for each slot/interval + get a print ready attendance sheet.
- manage athletes, with data like: birthday, category, covid certificate release date, etc.
- view and manage your slots in calendar view.
- view available slots without logging in, using a secret uinque url as authentication.
- book a slot according to your level and the type of session you need.
- view your booked slots in calendar view.
-
- ReactJS - open-source JavaScript library for building user interfaces.
-
- Firebase - Google's backend as a service with corresponding SDK(s)
-
- ESBuild - a lightning fast bundler/transpiler for JS (written in Go)
-
- Vite - a fully featured HMR dev-server, bundler and more, built on top of Parcel and ESBuild
-
- pnpm - a fast and storage efficient pacakge manager (pnpm stands for "performant npm")
-
- Rush - a monorepo management tool built for large projects, seamlessly integratable with pnpm, npm, yarn
-
- Click here to read about the CI infrastructure for the project
The entire repo is manaaged by Rush.
You don't need to install rush
or pnpm
.
You'll need to make sure the common/scripts
directory is found in the system PATH
.
If you're using direnv
this can be achieved by adding the line
PATH_add common/scripts/
to your .envrc file. The scripts directory also contains utility scripts, for instace to start the emulators or run firebase.
npm install -g @microsoft/rush
Additionally, we're using pnpm, which you can install manually or have Rush install for you. To install manually, run:
npm install -g pnpm
With management tools installed, run rush update
from any point in the repo to install all dependencies per package basis. Additionally, it makes sense to run rush build
in order to build all of the lib styled packages (shared, functions, etc.). The client app is built manually.
As the repo is managed by rush, we use rush
and rushx
commands for running of the scripts:
-
rushx
is a command similar tonpm run
oryarn
and is used to run a script from package.json, with a simple caveat: it needs to ba called from within a package, no--prefix
or--cwd
options -
rush <command>
can be used to run one of theglobal
/bulk
commands on the repo:- global command - if we, for instance, run
rush deploy:eisbuk
from enywhere in the repo, the built assets for the project will be deployed to a staging environment - bulk command - if we, for instance, run
rush lint:staged
from anywhere within the repo, thelint:staged
script of each package.json will be ran, which provides a convenient way linting all of the packages using single command - for all global/bluk commands, see command-line.json
- global command - if we, for instance, run
To add a dependency, you can simply run rush add --package <package_name>
don't use pnpm add or npm install, etc.. Additionally, you can add a dependency, manually, to package's package.json
, after which you need to run rush update
.
Make sure to check if it's already used elsewhere in the project. rush check
will notify about inconsistent versions. The script in .github/update_package.sh
can be used to change a version in all packages. Make sure you run rush update
and rush check
after using it.
To remove a dependency, simply remove it from package.json
and run rush update
The recommended node version for the monorepo is (as stated in .nvmrc
) 14.18.1
. If you're using nvm (and have the given node version installed), it's sufficient to run nvm use
anywhere in the repo to switch to appropriate version.
Some unexpected and cryptic errors might arise from a corrupt shrinkwrap file, at which point running the following might prove useful:
rush update --full
In order to work locally, we're leveraging the power of firebase emulator suite in lieu of firebase production backend.
To start the emulators, run:
emulators-start
This will run emulators for firebase services (auth, functions, firestore and hosting) with emulators dashboard at http://localhost:4000
You can add --inspect-functions 9229
to be able to connect with a debugger, for instance chrome from chrome://inspect/#devices or from the VSCode debugger.
With the emulators up and running, you can go ahead and start the dev server for the client app:
cd packages/client
rushx start
In order to start the development and observe in app functionality, you need to create the default admins.
Run the initDev
function from a browser console:
initDev();
This will create a default admin user and leave you logged in. If you want to sign out and sign back in, the credentials (for a default admin) are:
- email: "[email protected]"
- password: "test00"
Storybook is ran, as per usual, without the need for emulators. Simply run the storybook
command from the /client
app
cd packages/client
rushx storybook
To run JEST (unit) tests, run
cd packages/client
rushx test
There's no need to spin up the emulators as unit tests use different emulator set up and the emulators are (automatically) spun up when needed.
Running test
as in the above example runs all of the unit tests with full emulators support
Alternatively, you can run rushx test:quicktest
to run the tests without the emulators. This, however will skip all of the tests requiring emulator support.
To run E2E tests, you need to start up the emulators and the dev server (as in the first working flow) and additionally run cypress. First you need to
cd packages/e2e
From there, you can either run all e2e tests at once by running rush cypress:run
(more often used in CI), or, the more interactive way (preferred for development, TDD), open the Cypress dashboard by running rush cypress:open
The repo is structured as a monorepo, so each divisible unit of functionality is separated into its own package.
The packages are named by prepending @eisbuk
to each package name (as form of namespacing). The prefix, however, is omitted in the folder structure, i.e. path to @eisbuk/client
folder is /packages/client
, etc.
All of the packages have the same basic scripts (except for @eisbuk/scaffold
which doesn't utilize any functionality). Each package, then, features it's own additional scripts, but these are the standard ones:
build
- builds the app/lib using Vite/ESBuild (in case of library, builds bothesm
andcjs
versions), after build, runstypecheck
to generate the.d.ts
files, theres also a bulkrush build
command which runsbuild
in each packagelint
- lints the package (for development)lint:strict
- lints the package with failure if more than 0 errors/warnings (for pre-commit, CI), there's also a bulkrush lint:strict
command which runslint:strict
in each package (this is mostly used for CI, while the, singular,lint
script is used in dev)typecheck
- runs typescript check (for CI, with--noEmit
flag), there's also a bulkrush typecheck
command which runstypecheck
in each package
We currently feature the following packages:
The smallest of the packages, doesn't utilize any build process. Contains the "templates", more like base configs for eslint (.eslintrc.js
) and typescript (tsconfig.json
). We're using those files to provide a single source of truth (and simplify editing of the setup while preserving the consistency across the packages) as tsconfig.json
and .eslintrc.js
for each package are an extension of the base setup with some, would be, tweaks.
This folder contains some code: functions, enums, types, etc. shared among the @eisbuk/client
and "backend" (@eisbuk/functions
) app. The build process is done by Vite by running the build
script.
Similar to @eisbuk/shared
package, translations contains code shared among different packages, related to i18n, such as translation enums, translation dictionaries as well as i18next
setup. The build process is handled by Vite, in much the same way as @eisbuk/shared
package.
The functions package contains the code for "serverless" cloud functions. The functions are ran as part of the firebase emulators and, as part of CI/CD process, deployed, at production, to firebase "backend". The functions are built/served using ESBuild as a build tool, as Vite was an unnecessary complication at this point. The commands are build
and watch
.
The client package contains our main (browser) app. Currently all of our unit tests are contained within this package as well. The scripts connected to this package have already been explained above. The build/serve is handled by Vite, while unit tests are implemented using jest + react-testing-library.
Please note: client build process is a bit lengthier than that of the shared, functions, etc.. packages. Therefore, build
script in client package does nothing, not to slow down the bulk rush build
command. If you wish to build the @eisbuk/client
package for production, rushx build:prod
should be ran instead (from packages/client
)
The SVG package is used to store all .svg
files in one place. This is convenient for multiple reasons, but is not without challenges.
The pros of this approach is that we can use one standard SVG build mechanism and export all svg files as react components (prebuilt with SVGR). Additionally, having a single store of SVG assets allows us to externalize the deps of each package using .svg
s and bundle them in, only, with the final app. This prevents potentially bundling the same SVG twice (if the same SVG is used by ui
and client
packages, for instance). There's no need to mock .svg
files for tests as they already in as react components (prebuilt at imported package's build time).
The challenge, however, is that currently we don't have type declaration support for built SVGs: all SVGs are, in fact, react components, but are imported as any
,
which doesn't cause problems in a way of false positives, but is not completely kosher (we don't like any
assertions). However, this is a problem for another day.
Another challenge has to to with tree-shaking, where, however externalized, all SVGs from the packages/svg
get bundled in the final app.
Utilities for dumping and restoring organization data from an Eisbuk firestore instance. Documentation
In order to use SVGs, you can import svg (as named import from @eisbuk/svg
). If the SVG doesn't yet exist in the package, please provide a new one and add it as an export in packages/svg/src/index.ts
, like so:
import NewSVG from "./new-svg.svg";
export {
// ...other exports
NewSVG,
};
We're bundling SVGs using vite and SVGR plugin. By default values for width
and height
propertes on each SVG are replaced with 100%
allowing us to control the size of an SVG using a container element. In order to be able to color and SVG using color: <css-color-property>
, all colours hardcoded in an SVG source file need to be replaced with currentColor
. This has to be done manually as automating this could produce a myriad of problems.
A package containing automated, e2e tests using Cypress. All of the Cypress code, setup + integration are there and e2e tests should be ran from there (with assumption that some form of emulators/dev-server are already running)
EisBuk is a booking system developed for an ice skating school. It's open source, so if it fits your needs you can install it and use it.
If you want to contribute make sure you include tests for your change, and that existing tests don't break.