This project aims at serving a Single Page Application allowing a user to interact with its calendar.
This frontend application is built in a monorepo structure with Rsbuild, React, and TypeScript. It interacts with:
- esn-sabre CalDAV + CardDAV server, tailor made for LINAGORA needs.
- Twake Calendar side service that delivers additional backend features for Sabre.
It is meant as a drop-in replacement of esn-frontend-calendar.
The repository is organized as a monorepo workspace:
apps/private: The main private calendar application. Accessible by authenticated users.apps/public: The public calendar application. Used for public event previews and shared links.common: Shared components, hooks, translation locales, and utility functions used by both applications.
| Route | Description |
|---|---|
/ |
Login handler |
/calendar |
Main calendar view (authenticated) |
/events/:uid |
Deep link that opens the event identified by uid once the calendar is loaded (going through the login flow first when needed) |
/newEvent?attendee=alice@example.com |
Deep link that opens the create-event modal with the attendee(s) prefilled. Accepts several attendees, either repeated (?attendee=a@x.com&attendee=b@x.com) or comma separated (?attendee=a@x.com,b@x.com) |
/callback |
OAuth callback |
/error |
Error page |
| Route | Description |
|---|---|
/excal?jwt=${token} |
Event preview via JWT token |
/booking/${bookingLinkPublicId} |
Public booking page for a shared link |
We use Prettier to keep code style consistent.
A .prettierrc file is already included in the repo, so formatting rules are predefined.
Before committing, make sure you format your files either using your IDE Prettier extension or Prettier CLI.
Requirement: Node 24+
First, install the dependencies from the root directory:
npm installTo start the applications in development mode, use the following commands:
-
Private Application:
npm run start:private
Runs the private app on http://localhost:5000.
-
Public Application:
npm run start:public
Runs the public app on http://localhost:5001.
To build the applications for production, run:
-
Build Both Apps:
npm run build
-
Build Private App Only:
npm run build:private
-
Build Public App Only:
npm run build:public
The production bundles will be compiled to apps/private/dist and apps/public/dist respectively.
You can serve the built production assets locally using:
-
Serve Private App:
npm run serve:private
Serves on http://localhost:5000.
-
Serve Public App:
npm run serve:public
Serves on http://localhost:5001.
Launches the Jest test runner:
npm testTo run the ESLint checks:
npm run lintTo automatically fix formatting and lint errors:
npm run lint:fixFirst, build the applications:
npm run buildThen build the Docker image for the specific application:
# For private app:
docker build -f apps/private/Dockerfile -t linagora/twake-calendar-private .
# For public app:
docker build -f apps/public/Dockerfile -t linagora/twake-calendar-public .To run the container, mount the .env.js configuration file from the root public/ directory:
docker run -d \
-v $PWD/public/.env.js:/usr/share/nginx/html/.env.js \
-p 5000:80 \
linagora/twake-calendar-privateThe applications load configuration dynamically at runtime from static JavaScript files in the public directory.
- Copy
public/.env.example.jstopublic/.env.js - Customize the variables in
public/.env.jsto match your environment.
The Public App (apps/public) requires three specific environment variables to be defined in .env.js to configure external links in the user interface (such as help buttons and terms/privacy links in the page footers):
SUPPORT_URL: The URL for the "Need help" button located in the top-right header of the public layout.PRIVACY_URL: The URL for the "Privacy Policy" link in the footer of the public layout.TERMS_URL: The URL for the "Terms of Service" link in the footer of the public layout.
Example .env.js snippet:
var SUPPORT_URL = 'https://twake.com/help'
var PRIVACY_URL = 'https://twake.com/privacy'
var TERMS_URL = 'https://twake.com/terms'An applist is configurable in the public folder to setup the grid of apps accessible within Twake Calendar (private app).
- Copy
public/appList.example.jstopublic/appList.js - Place your app icons in
public/assets/images/svg/directory - Configure each app with three fields:
name: the app's nameicon: the path to the app's icon (relative to public folder, e.g.,/assets/images/svg/app-chat.svg)link: the app's link or URL
Example:
var appList = [
{
name: 'Chat',
link: '/twake',
icon: '/assets/images/svg/app-chat.svg'
},
{
name: 'Drive',
link: '/drive',
icon: '/assets/images/svg/app-drive.svg'
},
{
name: 'Mail',
link: '/mail',
icon: '/assets/images/svg/app-mail.svg'
}
]Note: appList.js and .env.js are gitignored, so each environment can have its own configuration.
Now that we delivered all features in esn-frontend-calendar we plan to work on even more exciting features:
- Provide Booking links that allow people you send it to to book easily meeting with you, based on your availability.
- Deliver Drive integration in order to attach files to your events
- Team Calendar that would hold events of a team
Stay tuned!
Developed with <3 at LINAGORA !
