Skip to content

Commit bb00e36

Browse files
committed
improved appointment formatting
1 parent 3aa05e5 commit bb00e36

File tree

5 files changed

+75
-43
lines changed

5 files changed

+75
-43
lines changed

src/components/App.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class App extends Component {
1616
enquiry_form_info: null,
1717
}
1818
this.url = props.url_generator
19-
this.get_text = this.get_text.bind(this)
19+
this.get_text = (...args) => this.props.config.get_text(...args)
2020

2121
this.get_enquiry = this.get_enquiry.bind(this)
2222
this.set_enquiry = this.set_enquiry.bind(this)
@@ -28,18 +28,6 @@ class App extends Component {
2828
}
2929
}
3030

31-
get_text (name, replacements) {
32-
let s = this.props.config.messages[name]
33-
if (!s) {
34-
console.warn(`not translation found for "${name}"`)
35-
return name
36-
}
37-
for (let [k, v] of Object.entries(replacements || {})) {
38-
s = s.replace(`{${k}}`, v)
39-
}
40-
return s
41-
}
42-
4331
get_enquiry () {
4432
if (this.state.enquiry_form_info === null) {
4533
async_start(this.set_enquiry)

src/components/appointments/Appointments.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ const AptDayGroup = ({appointments, props}) => {
3434
<span>{apt.topic} ({apt.service_name})</span>
3535
</div>
3636
<div>
37-
<span>{props.config.format_time_diff(apt.finish, apt.start, props.config)}</span>&bull;
38-
<span>£{apt.price}</span>
37+
<span>{props.config.format_time_diff(apt.finish, apt.start)}</span>&bull;
38+
<span>{props.config.format_money(apt.price)}</span>
3939
</div>
4040
</div>
4141
</Link>

src/components/appointments/AptModal.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class AptModal extends Component {
1414
this.check_client = this.check_client.bind(this)
1515
this.signout = this.signout.bind(this)
1616
this.book = this.book.bind(this)
17-
this.get_srs = this.get_srs.bind(this)
17+
this.get_students = this.get_students.bind(this)
1818
this.state = {
1919
apt: props.appointments && props.appointments.find(a => a.id === this.apt_id),
2020
signature: null,
@@ -74,7 +74,7 @@ class AptModal extends Component {
7474
const r = await this.props.root.requests.get('check-client', args, {set_app_state: false})
7575
this.setState({appointment_attendees: r.appointment_attendees[this.apt_id] || [], booking_allowed: true})
7676
} catch (e) {
77-
if (e.xhr.status === 403) {
77+
if (e.xhr.status === 401) {
7878
this.signout()
7979
} else {
8080
this.props.root.setState({error: e.msg})
@@ -122,7 +122,7 @@ class AptModal extends Component {
122122
window.sessionStorage.removeItem(LS_KEY)
123123
}
124124

125-
get_srs () {
125+
get_students () {
126126
return this.state.display_data && Object.entries(this.state.display_data.srs).map(([k, name]) => {
127127
const sr_id = parseInt(k, 10)
128128
return {
@@ -155,15 +155,15 @@ class AptModal extends Component {
155155
{apt.topic}
156156
</span>
157157
)
158-
const srs = this.get_srs()
158+
const students = this.get_students()
159159
const spaces_available = apt.attendees_max - apt.attendees_count - this.state.extra_attendees
160160
const booking_allowed = this.state.booking_allowed && spaces_available > 0
161161
return (
162162
<Modal history={this.props.history} title={title} last_url={this.props.last_url} flex={false}>
163163
<div className="tcs-modal-flex">
164164
<div className="tcs-extra">
165165
<div className="tcs-price">
166-
£{apt.price}
166+
{this.props.config.format_money(apt.price)}
167167
<div className="tcs-label">Price</div>
168168
</div>
169169
</div>
@@ -194,10 +194,10 @@ class AptModal extends Component {
194194
<div className="tcs-book">
195195
<IfElse v={this.state.display_data}>
196196
<div>
197-
{srs && (
197+
{students && (
198198
<div className="tcs-book-existing">
199199
<div>Add your existing Students to the lesson</div>
200-
{srs.map(({id, name, already_on_apt}) => (
200+
{students.map(({id, name, already_on_apt}) => (
201201
<div key={id} className="tcs-book-item">
202202
<div className="tcs-existing-name">
203203
{name}

src/formatting.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
export function get_text (name, replacements) {
2+
let s = this.messages[name]
3+
if (!s) {
4+
console.warn(`not translation found for "${name}"`)
5+
return name
6+
}
7+
if (replacements) {
8+
for (let [k, v] of Object.entries(replacements)) {
9+
s = s.replace(`{${k}}`, v)
10+
}
11+
}
12+
return s
13+
}
14+
15+
export function format_money (amount) {
16+
const symbol = this.currency ? this.currency.symbol : ''
17+
if (amount % 1 === 0) {
18+
return symbol + amount
19+
} else {
20+
return symbol + amount.toFixed(2)
21+
}
22+
}
23+
24+
export function format_date (ts) {
25+
return this.date_fns.format(new Date(ts), this.format.date)
26+
}
27+
28+
export function format_datetime (ts) {
29+
return this.date_fns.format(new Date(ts), this.format.datetime)
30+
}
31+
32+
export function format_time_diff (ts1, ts2) {
33+
const d1 = new Date(ts1)
34+
const d2 = new Date(ts2)
35+
let minutes = Math.round((d1 - d2) / 60000)
36+
if (minutes === 60) {
37+
return this.get_text('diff_1hour')
38+
}
39+
if (minutes < 60) {
40+
return this.get_text('diff_minutes', {minutes})
41+
}
42+
const hours = Math.floor(minutes / 60)
43+
minutes = minutes % 60
44+
if (hours === 1) {
45+
return this.get_text('diff_1hour_minutes', {minutes})
46+
}
47+
if (minutes === 0) {
48+
return this.get_text('diff_hours', {hours})
49+
} else {
50+
return this.get_text('diff_hours_minutes', {hours, minutes})
51+
}
52+
}

src/index.js

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import React from 'react'
33
import ReactDOM from 'react-dom'
44
import 'babel-polyfill'
55
import format from 'date-fns/format'
6-
import distanceInWordsStrict from 'date-fns/distance_in_words_strict'
76
import './main.scss'
87
import App from './components/App'
98
import {BrowserRouter, HashRouter} from 'react-router-dom'
109
import {auto_url_root, get_company_options} from './utils'
10+
import {format_date, format_datetime, format_money, format_time_diff, get_text} from './formatting'
1111

1212
const raven_config = {
1313
release: process.env.REACT_APP_RELEASE,
@@ -52,6 +52,11 @@ const STRINGS = {
5252
distance_away: '{distance}km away',
5353
book_appointment_button: 'Book Lesson',
5454
add_to_lesson: 'Add to Lesson',
55+
diff_minutes: '{minutes} minutes',
56+
diff_1hour: '1 hour',
57+
diff_1hour_minutes: '1 hour {minutes} minutes',
58+
diff_hours: '{hours} hours',
59+
diff_hours_minutes: '{hours} hours {minutes} minutes',
5560
}
5661

5762
const MODES = ['grid', 'list', 'enquiry', 'enquiry-modal', 'appointments']
@@ -129,32 +134,19 @@ window.socket = async function (public_key, config) {
129134
datetime: 'HH:mm DD/MM/YYYY',
130135
date: 'DD/MM/YYYY'
131136
}
132-
config.date_fns = {format, distanceInWordsStrict}
133-
config.format_date = config.date_format || (
134-
function (ts) {return this.date_fns.format(new Date(ts), this.format.date)}
135-
)
136-
config.format_date = config.format_date.bind(config)
137-
138-
config.format_datetime = config.format_datetime || (
139-
function (ts) {return this.date_fns.format(new Date(ts), this.format.datetime)}
140-
)
141-
config.format_datetime = config.format_datetime.bind(config)
142-
config.format_time_diff = config.format_time_diff || (
143-
(ts1, ts2, config) => config.date_fns.distanceInWordsStrict(new Date(ts1), new Date(ts2))
144-
)
137+
config.date_fns = {format}
138+
config.format_date = (config.date_format || format_date).bind(config)
139+
config.format_datetime = (config.format_datetime || format_datetime).bind(config)
140+
config.format_time_diff = (config.format_time_diff || format_time_diff).bind(config)
141+
config.format_money = (config.format_money || format_money).bind(config)
145142

146143
const el = document.querySelector(config.element)
147144
if (el === null) {
148145
config.console.error(`SOCKET: page element "${config.element}" does not exist, unable to start socket view.`)
149146
return
150147
}
151-
152-
config.messages = config.messages || {}
153-
for (let k of Object.keys(STRINGS)) {
154-
if (!config.messages[k]) {
155-
config.messages[k] = STRINGS[k]
156-
}
157-
}
148+
config.messages = Object.assign(Object.assign({}, STRINGS), config.messages || {})
149+
config.get_text = (config.get_text || get_text).bind(config)
158150
config.random_id = Math.random().toString(36).substring(2, 10)
159151
config.grecaptcha_key = process.env.REACT_APP_GRECAPTCHA_KEY
160152

0 commit comments

Comments
 (0)