Guided Tour Overview
What is the guided tour?
To guide new users of the app through learning the functionalities of map planning we have the guided tour.
When a new user opens their first map they immediately enter the tour.
The tour consists of multiple steps that appear as popups for the user and give some information about app functions or ask the user to complete some simple actions.
The tour can be paused or dismissed at any step in the tour.
Every pause increases the time the tour is not shown again to the user. (maxing out at 30 days)
Backend
There are 2 database tables used in the context of the guided tour; guided_tour_progress and guided_tour_states.
guided_tour_progress
| Column | Data Type | Description |
|---|---|---|
| user_id | uuid | Unique identifier of the user |
| step_key | text | Identifier of the guided tour step |
| completed_at | timestamp(0) without time zone | Timestamp when the step was completed |
guided_tour_progress is used to track the tour progress of all users.
If an entry exists for a user id and a step key this user has completed that step.
guided_tour_states
| Column | Data Type | Description |
|---|---|---|
| user_id | uuid | Unique identifier of the user |
| paused_at | timestamp(0) without time zone | Timestamp when the tour was paused |
| pause_count | integer | Number of times the tour was paused |
guided_tour_states is used to track if a user has paused their tour.
There is a row for each user that has paused their tour at least once.
paused_at and pause_count determine if the tour is still paused.
Endpoints
The backend contains endpoints to interact with these tables (controller/guided_tour.rs):
- pause (POST): increments
pause_countand setspaused_attonow()for the requesting user. - complete_step (POST): marks the singular transmitted step key as completed in the database for the requesting user.
- complete_steps_bulk (POST): marks all transmitted step keys as completed in the database for the requesting user.
- find_by_user (GET): returns a list of all completed step keys and a boolean specifying if the tour is currently paused for the requesting user.
The boolean specifying if the tour is still paused is derived from paused_at and pause_count of the requesting user.
The pause duration is determined by the Fibonacci number corresponding to pause_count, capped at 30 days.
This is calculated in backend/model/dto/guided_tour_impl.rs:
/// How many days not to show the tour based on `pause_count`
/// Fibonacci with max of 30 days
fn backoff_days(pause_count: i32) -> i64 {
if pause_count <= 0 {
return 0;
}
let n = pause_count;
let mut a: i64 = 0;
let mut b: i64 = 1;
for _ in 0..n {
let temp = a;
a = b;
b += temp;
}
a.min(30)
}
The tour remains paused as long as the current timestamp of the backend is earlier than paused_at plus this computed duration.
Frontend
Sheperd.js is the framework we use for the guided tour frontend.
What step keys exist and what their corresponding tour steps do is defined in the frontend.
The guided tour is initialized in MapWrapper.ts.
This is where the backend call is made to check what steps the user has already completed and if their tour is currently paused.
If the backend returns that the tour is currently paused then nothing is shown to the user.
If the tour is not currently paused for the user then the completed step keys from the backend are compared to the list of steps currently defined in the frontend.
This ensures that steps which have already been completed are not shown again and the user resumes their tour where they left off last time.
Users who previously completed the entire tour will only see newly added steps that were introduced after their tour completion.
This is done in this part of MapWrapper.ts:
const steps = useMemo(() => {
if (tourStatus.paused || isReadOnly) return [];
return guidedTourSteps(tourStatus.completed_steps ?? []);
}, [tourStatus.completed_steps, tourStatus.paused, isReadOnly]);
The tour is also not shown if the user entered a readonly map.
This is what isReadOnly does in the code.
guidedTourSteps(...) is a function from the util file GuidedTour.ts and contains the definition of all the steps currently featured in the guided tour.
It takes the completed tour step keys from the backend as an argument and detracts them from all steps included in the tour.
It then returns only the steps that are not yet marked as completed and should be shown.
The returned steps are used in MapWrapper.ts to initialize the tour.
More detailed information about step definition and how to add new steps is included in adding_guided_tour_steps.md.
Guided Tour Coverage
This section details what parts of the map editor are currently covered by the guided tour.
What app functionality is currently covered by the tour:
- Welcome
- Toolbox intro
- Layers panel
- Timeline
- Plant placement
- Search
- Select
- Place
- Edit
- Delete
- Remove
- Undo functionality
- Plant relationships (allies/antagonists)
What is currently NOT covered:
- Selecting base layer image
- Scaling base layer image
- Setting map boundaries
- Copy/paste/cut functionality (Toolbox.tsx:150-173)
- Shading and other environmental factors layers (ShadeLayer.tsx etc.)
- Toolbar buttons
- Grid
- Labels
- Markers
- Measurement toggle
- Layer creation functionality
- Reordering layers
- Renaming layers
- Deleting layers
- Dark and light mode
- Toolbar hide/show functionality
- Drawing layer
- Drawing
- Adding text
- Adding pictures