Skip to content

Commit f72811b

Browse files
committed
Feature: Onboarding page for self-hosted installations
1 parent 251f83b commit f72811b

File tree

7 files changed

+171
-6
lines changed

7 files changed

+171
-6
lines changed

app/controllers/metadata_controller.rb

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ def index
2323
render json: {
2424
latest_version: data["latest_version"],
2525
installed_version: installed_version,
26-
version_ignored: data["version_ignored"]
26+
version_ignored: data["version_ignored"],
27+
onboarded: data["onboarded"] || false
2728
}
2829
end
2930

@@ -34,6 +35,27 @@ def skip_version
3435
Metadatum.first.update(data: data)
3536
end
3637

38+
def skip_onboarding
39+
data = Metadatum.first&.data
40+
data["onboarded"] = true
41+
Metadatum.first.update(data: data)
42+
end
43+
44+
def finish_installation
45+
46+
name = params[:name]
47+
email = params[:email]
48+
49+
response = HTTParty.post('https://hub.tooljet.io/subscribe',
50+
verify: false,
51+
body: { name: name, email: email, installed_version: TOOLJET_VERSION }.to_json,
52+
headers: { "Content-Type" => "application/json" })
53+
54+
data = Metadatum.first&.data
55+
data["onboarded"] = true
56+
Metadatum.first.update(data: data)
57+
end
58+
3759
private
3860
def check_for_updates(current_data, installed_version)
3961

config/application.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
# you've limited to :test, :development, or :production.
2020
Bundler.require(*Rails.groups)
2121

22+
TOOLJET_VERSION = '0.5.3'
23+
2224
module ToolJet
2325
class Application < Rails::Application
2426
# Initialize configuration defaults for originally generated Rails version.

config/routes.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
resources :metadata, only: [:index] do
4646
collection do
4747
post '/skip_version', to: 'metadata#skip_version'
48+
post '/skip_onboarding', to: 'metadata#skip_onboarding'
49+
post '/finish_installation', to: 'metadata#finish_installation'
4850
end
4951
end
5052

frontend/src/App/App.jsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@ import '@/_styles/theme.scss';
1313
import { ToastContainer } from 'react-toastify';
1414
import 'react-toastify/dist/ReactToastify.css';
1515
import { ManageOrgUsers } from '@/ManageOrgUsers';
16+
import { OnboardingModal } from '@/Onboarding/OnboardingModal';
1617

1718
class App extends React.Component {
1819
constructor(props) {
1920
super(props);
2021

2122
this.state = {
2223
currentUser: null,
23-
fetchedMetadata: false
24+
fetchedMetadata: false,
25+
onboarded: true
2426
};
2527
}
2628

@@ -36,11 +38,11 @@ class App extends React.Component {
3638
}
3739

3840
render() {
39-
const { currentUser, fetchedMetadata, updateAvailable } = this.state;
41+
const { currentUser, fetchedMetadata, updateAvailable, onboarded } = this.state;
4042

4143
if(currentUser && fetchedMetadata === false) {
4244
tooljetService.fetchMetaData().then((data) => {
43-
this.setState({ fetchedMetadata: true });
45+
this.setState({ fetchedMetadata: true, onboarded: data.onboarded });
4446

4547
if(data.installed_version < data.latest_version && data.version_ignored === false) {
4648
this.setState({ updateAvailable: true });
@@ -60,6 +62,10 @@ class App extends React.Component {
6062
</div>
6163
</div>}
6264

65+
{!onboarded &&
66+
<OnboardingModal />
67+
}
68+
6369
<ToastContainer />
6470

6571
<PrivateRoute exact path="/" component={HomePage} />
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import React from 'react';
2+
import { tooljetService } from '@/_services';
3+
import Modal from 'react-bootstrap/Modal';
4+
5+
class OnboardingModal extends React.Component {
6+
constructor(props) {
7+
super(props);
8+
9+
this.state = {
10+
showModal: true,
11+
options: {
12+
13+
}
14+
};
15+
}
16+
17+
componentDidMount() {
18+
}
19+
20+
hideModal = () => {
21+
this.setState({
22+
showModal: false
23+
});
24+
};
25+
26+
finishOnboarding = () => {
27+
this.setState({
28+
showModal: false
29+
});
30+
31+
tooljetService.finishOnboarding(this.state.options);
32+
}
33+
34+
skipOnboard = () => {
35+
tooljetService.skipOnboarding();
36+
this.setState({showModal: false});
37+
}
38+
39+
changeOptions = (option, value) => {
40+
this.setState({
41+
options: {
42+
...this.state.options,
43+
[option]: value
44+
}
45+
});
46+
};
47+
48+
49+
render() {
50+
51+
return (
52+
<Modal show={this.state.showModal} size="md" backdrop="static" centered={true} keyboard={true} onEscapeKeyDown={this.hideModal}>
53+
<Modal.Header>
54+
<Modal.Title className="text-center">
55+
Finish ToolJet installation
56+
</Modal.Title>
57+
</Modal.Header>
58+
59+
<Modal.Body>
60+
<h3>Receive product updates from the ToolJet team? </h3>
61+
<small>We hate spam and we will never spam</small>
62+
63+
<input
64+
onChange={(e) => onComponentOptionChanged(component, 'value', e.target.value)}
65+
type="text"
66+
className="form-control mt-3"
67+
placeholder={'Your name'}
68+
onChange={(e) => {
69+
this.changeOptions('name', e.target.value);
70+
}}
71+
/>
72+
73+
<input
74+
onChange={(e) => onComponentOptionChanged(component, 'value', e.target.value)}
75+
type="text"
76+
className="form-control mt-3"
77+
placeholder={'Your email'}
78+
onChange={(e) => {
79+
this.changeOptions('email', e.target.value);
80+
}}
81+
/>
82+
83+
</Modal.Body>
84+
85+
<Modal.Footer>
86+
<div className="row w-100">
87+
<div className="col">
88+
<button
89+
className={`btn btn-primary`}
90+
onClick={this.finishOnboarding}
91+
>
92+
Finish setup
93+
</button>
94+
</div>
95+
<div className="col-auto">
96+
<a onClick={this.skipOnboard} className="mt-2">
97+
Skip
98+
</a>
99+
</div>
100+
</div>
101+
102+
103+
</Modal.Footer>
104+
</Modal>
105+
);
106+
}
107+
}
108+
109+
export { OnboardingModal };

frontend/src/_components/Header.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { useState, useEffect } from 'react';
22
import { Link } from 'react-router-dom';
33
import { authenticationService } from '@/_services';
4+
import { history } from '@/_helpers';
45

56
export const Header = function Header({
67

frontend/src/_services/tooljet.service.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import { authHeader, handleResponse } from '@/_helpers';
33

44
export const tooljetService = {
55
fetchMetaData,
6-
skipVersion
6+
skipVersion,
7+
skipOnboarding,
8+
finishOnboarding
79
};
810

911
function fetchMetaData() {
@@ -22,4 +24,25 @@ function skipVersion() {
2224
};
2325

2426
return fetch(`${config.apiUrl}/metadata/skip_version`, requestOptions).then(handleResponse);
25-
}
27+
}
28+
29+
function skipOnboarding() {
30+
const requestOptions = {
31+
method: 'POST',
32+
headers: authHeader()
33+
};
34+
35+
return fetch(`${config.apiUrl}/metadata/skip_onboarding`, requestOptions).then(handleResponse);
36+
}
37+
38+
function finishOnboarding(options) {
39+
const requestOptions = {
40+
method: 'POST',
41+
headers: authHeader(),
42+
body: JSON.stringify({
43+
...options
44+
})
45+
};
46+
47+
return fetch(`${config.apiUrl}/metadata/finish_installation`, requestOptions).then(handleResponse);
48+
}

0 commit comments

Comments
 (0)