Skip to content

Commit

Permalink
feat: #781 Book a viewing (#931)
Browse files Browse the repository at this point in the history
* feat: #781 I want to click button to arrange a viewing with Estate Agent

* chore: #781 update style

* chore: add some test

* chore: #781 update theme class

* chore: #781 update styles

Co-authored-by: andt <[email protected]>
ant066 and andt-dwarvesv authored Apr 20, 2020
1 parent 54025f2 commit 629fb15
Showing 21 changed files with 1,100 additions and 154 deletions.
70 changes: 69 additions & 1 deletion packages/web-components/src/common/components/modal.svelte
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
import ClickOutSide from './click-out-side.svelte'
export let isModalOpen
export let toggleModal
export let title = 'Modal Title'
</script>

<style>
@@ -17,12 +18,79 @@
background: #00000052;
z-index: 1;
}
@media only screen and (min-width: 48rem) {
.reapit-modal-wrapper .reapit-modal {
top: 50%;
left: 50%;
width: auto;
height: auto;
transform: translate(-50%, -50%);
border-radius: 0.25em;
overflow: hidden;
max-width: 80%;
position: fixed;
}
}
.reapit-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
min-width: 50%;
font-size: 16px;
background: #ffffff;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
overflow: hidden;
}
.reapit-modal-wrapper .modal-title {
font-weight: 600;
border-bottom: 1px solid #ddd;
margin: 0;
text-align: center;
font-size: 1em;
padding: 1em 3em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.reapit-modal-wrapper .modal-close {
position: absolute;
top: 0;
left: 0;
padding: 1em 1.2em;
cursor: pointer;
}
.reapit-modal-wrapper .modal-close:hover {
background: #ddd;
}
.reapit-modal-wrapper .modal-close-btn {
transform: rotate(135deg);
-webkit-transform: rotate(135deg);
border: solid black;
border-width: 0 2px 2px 0;
display: inline-block;
padding: 4px;
cursor: pointer;
}
</style>

{#if isModalOpen}
<div class="reapit-modal-wrapper">
<ClickOutSide on:click-out-side={toggleModal}>
<slot />
<div class="reapit-modal">
<div class="modal-close" on:click={toggleModal}>
<i class="modal-close-btn" />
</div>
<h3 class="modal-title" {title}>{title}</h3>
<div class="modal-content">
<slot />
</div>
</div>
</ClickOutSide>
</div>
{/if}
Original file line number Diff line number Diff line change
@@ -178,7 +178,7 @@ exports[`styles should generate a reset css class 1`] = `"css-h4w50h"`;
exports[`styles should generate an object of CSS classes 1`] = `
Object {
"bodyText": "css-11v9sqy",
"button": "css-naokd4",
"button": "css-1tgg1a8",
"globalStyles": "css-ya093n",
"input": "css-u6oic2",
"offerBanner": "css-gl5ek3",
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const defaultVariant = {
baseBackgroundColor: '#f9fbfd',
basefontSize: '16px',
basefontColor: '#12263f',
inverseFontColor: '#f9fbfd',
secondaryfontColor: '#1e2554',
primaryHeadingFontSize: '24px',
secondaryHeadingFontSize: '20px',
baseFontFamily: '"Roboto", sans-serif',
headingFontFamily: '"Open Sans", sans-serif',
primaryAccentColor: '#0061a8',
secondaryAccentColor: '#6c757d',
mapAccentColor: '#7bc9eb',
breakPoints: {
mobile: '',
tablet: '',
laptop: '',
desktop: '',
},
}

window.theme = defaultVariant
7 changes: 1 addition & 6 deletions packages/web-components/src/common/styles/theme.ts
Original file line number Diff line number Diff line change
@@ -118,16 +118,11 @@ export const generateThemeClasses = (
color: ${primaryAccentColor || '#000'};
border: 1px solid ${primaryAccentColor || 'grey'};
background: ${baseBackgroundColor || '#fff'};
color: ${inverseFontColor || 'grey'};
&:hover {
background: ${inverseFontColor || 'grey'};
background: ${primaryAccentColor || 'grey'};
color: ${baseBackgroundColor || '#fff'};
}
&:last-child {
border-left: none;
}
}
`,
input: css`
19 changes: 19 additions & 0 deletions packages/web-components/src/common/utils/__tests__/validate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { validateEmail } from '../validate'

describe('validate email', () => {
it('should return true', () => {
const mail = '[email protected]'
expect(validateEmail(mail)).toBe(true)
})

it('should return false', () => {
let mail = 'abcedf.com'
expect(validateEmail(mail)).toBe(false)

mail = '[email protected]'
expect(validateEmail(mail)).toBe(false)

mail = 'abc@edf'
expect(validateEmail(mail)).toBe(false)
})
})
5 changes: 5 additions & 0 deletions packages/web-components/src/common/utils/validate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function validateEmail(email: string) {
//eslint-disable-next-line
const regex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return regex.test(email)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import svelte from 'rollup-plugin-svelte'
import baseConfig from './rollup.config.base'
import replace from '@rollup/plugin-replace'
import path from 'path'

const config = require(path.resolve(__dirname, '../..', 'config.json'))
const production = !process.env.ROLLUP_WATCH

export default {
...baseConfig,
input: 'src/viewing-booking/client/core/index.ts',
output: {
sourcemap: !production,
format: 'iife',
name: 'app',
file: './public/dist/viewing-booking.js',
},
plugins: [
svelte({
dev: !production,
css: css => {
css.write('./public/dist/viewing-booking.css')
},
}),
replace({
'process.env.NODE_ENV': JSON.stringify(config.NODE_ENV),
}),
...baseConfig.plugins,
],
}
Original file line number Diff line number Diff line change
@@ -152,18 +152,13 @@ exports[`search-widget it matches a snapshot 1`] = `
color: #000;
border: 1px solid grey;
background: #fff;
color: grey;
}
#search-widget .emotion-1:hover {
background: grey;
color: #fff;
}
#search-widget .emotion-1:last-child {
border-left: none;
}
#search-widget .emotion-0 {
font-family: Helvetica,Arial,sans-serif;
font-size: 18px;
Original file line number Diff line number Diff line change
@@ -4,88 +4,111 @@ exports[`EnlargeImageModal should match snapshot 1`] = `
<body>
<div>
<div
class="reapit-modal-wrapper svelte-1w7voj9"
class="reapit-modal-wrapper svelte-dwjkb3"
>
<div>
<div
class="light-box-enlarge-image-modal svelte-19txmtp"
style="width: 819.2px; height: 614.4000000000001px;"
class="reapit-modal svelte-dwjkb3"
>
<img
alt="Current carousel display image"
class="light-box-enlarge-image svelte-19txmtp"
src="current-display-image-url"
/>
<div
class="modal-close svelte-dwjkb3"
>
<i
class="modal-close-btn svelte-dwjkb3"
/>
</div>
<h3
class="modal-title svelte-dwjkb3"
title="Modal Title"
>
Modal Title
</h3>
<div
class="light-box-widget-container svelte-19txmtp"
class="modal-content"
>
<div>
<button
class="light-box-widget-prev-button"
<div
class="light-box-enlarge-image-modal svelte-19txmtp"
style="width: 819.2px; height: 614.4000000000001px;"
>
<img
alt="Current carousel display image"
class="light-box-enlarge-image svelte-19txmtp"
src="current-display-image-url"
/>
<div
class="light-box-widget-container svelte-19txmtp"
>
<svg
aria-hidden="true"
class=""
id=""
role="img"
style="height:1em;vertical-align:-.125em;overflow:visible;"
viewBox="0 0 320 512"
xmlns="http://www.w3.org/2000/svg"
>
<g
transform="translate(256 256)"
<div>
<button
class="light-box-widget-prev-button"
>
<g
transform=""
<svg
aria-hidden="true"
class=""
id=""
role="img"
style="height:1em;vertical-align:-.125em;overflow:visible;"
viewBox="0 0 320 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"
fill="currentColor"
transform="translate(-256 -256)"
/>
</g>
</g>
</svg>
</button>
<span
data-testid="light-box-widget-item-quantity"
>
1
of
10
</span>
<button
class="light-box-widget-next-button svelte-19txmtp"
>
<svg
aria-hidden="true"
class=""
id=""
role="img"
style="height:1em;vertical-align:-.125em;overflow:visible;"
viewBox="0 0 320 512"
xmlns="http://www.w3.org/2000/svg"
>
<g
transform="translate(256 256)"
<g
transform="translate(256 256)"
>
<g
transform=""
>
<path
d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"
fill="currentColor"
transform="translate(-256 -256)"
/>
</g>
</g>
</svg>
</button>
<span
data-testid="light-box-widget-item-quantity"
>
1
of
10
</span>
<button
class="light-box-widget-next-button svelte-19txmtp"
>
<g
transform=""
<svg
aria-hidden="true"
class=""
id=""
role="img"
style="height:1em;vertical-align:-.125em;overflow:visible;"
viewBox="0 0 320 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"
fill="currentColor"
transform="translate(-256 -256)"
/>
</g>
</g>
</svg>
</button>
<g
transform="translate(256 256)"
>
<g
transform=""
>
<path
d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"
fill="currentColor"
transform="translate(-256 -256)"
/>
</g>
</g>
</svg>
</button>
</div>
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -4,88 +4,111 @@ exports[`Carousel should match snapshot 1`] = `
<body>
<div>
<div
class="reapit-modal-wrapper svelte-1w7voj9"
class="reapit-modal-wrapper svelte-dwjkb3"
>
<div>
<div
class="light-box-enlarge-image-modal svelte-19txmtp"
style="width: 819.2px; height: 614.4000000000001px;"
class="reapit-modal svelte-dwjkb3"
>
<img
alt="Current carousel display image"
class="light-box-enlarge-image svelte-19txmtp"
src="current-display-image-url"
/>
<div
class="modal-close svelte-dwjkb3"
>
<i
class="modal-close-btn svelte-dwjkb3"
/>
</div>
<h3
class="modal-title svelte-dwjkb3"
title="Modal Title"
>
Modal Title
</h3>
<div
class="light-box-widget-container svelte-19txmtp"
class="modal-content"
>
<div>
<button
class="light-box-widget-prev-button"
<div
class="light-box-enlarge-image-modal svelte-19txmtp"
style="width: 819.2px; height: 614.4000000000001px;"
>
<img
alt="Current carousel display image"
class="light-box-enlarge-image svelte-19txmtp"
src="current-display-image-url"
/>
<div
class="light-box-widget-container svelte-19txmtp"
>
<svg
aria-hidden="true"
class=""
id=""
role="img"
style="height:1em;vertical-align:-.125em;overflow:visible;"
viewBox="0 0 320 512"
xmlns="http://www.w3.org/2000/svg"
>
<g
transform="translate(256 256)"
<div>
<button
class="light-box-widget-prev-button"
>
<g
transform=""
<svg
aria-hidden="true"
class=""
id=""
role="img"
style="height:1em;vertical-align:-.125em;overflow:visible;"
viewBox="0 0 320 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"
fill="currentColor"
transform="translate(-256 -256)"
/>
</g>
</g>
</svg>
</button>
<span
data-testid="light-box-widget-item-quantity"
>
1
of
10
</span>
<button
class="light-box-widget-next-button svelte-19txmtp"
>
<svg
aria-hidden="true"
class=""
id=""
role="img"
style="height:1em;vertical-align:-.125em;overflow:visible;"
viewBox="0 0 320 512"
xmlns="http://www.w3.org/2000/svg"
>
<g
transform="translate(256 256)"
<g
transform="translate(256 256)"
>
<g
transform=""
>
<path
d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"
fill="currentColor"
transform="translate(-256 -256)"
/>
</g>
</g>
</svg>
</button>
<span
data-testid="light-box-widget-item-quantity"
>
1
of
10
</span>
<button
class="light-box-widget-next-button svelte-19txmtp"
>
<g
transform=""
<svg
aria-hidden="true"
class=""
id=""
role="img"
style="height:1em;vertical-align:-.125em;overflow:visible;"
viewBox="0 0 320 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"
fill="currentColor"
transform="translate(-256 -256)"
/>
</g>
</g>
</svg>
</button>
<g
transform="translate(256 256)"
>
<g
transform=""
>
<path
d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"
fill="currentColor"
transform="translate(-256 -256)"
/>
</g>
</g>
</svg>
</button>
</div>
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -66,7 +66,7 @@ Search_widget {
"selectedProperty": null,
"themeClasses": Object {
"bodyText": "css-11v9sqy",
"button": "css-naokd4",
"button": "css-1tgg1a8",
"globalStyles": "css-ya093n",
"input": "css-u6oic2",
"offerBanner": "css-gl5ek3",
10 changes: 10 additions & 0 deletions packages/web-components/src/viewing-booking/client/api/property.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { PropertyData } from '../core'

export const getProperty = async (): Promise<PropertyData> => {
return Promise.resolve({
image:
'https://tracker.reapit.net/demo/_demo/webservice/rest/property/rps_demo-SCO190002/thumbnail?ApiKey=8ed799bbe77c96311e71f64b99ec2ddde765d13a&Width=480&Height=285&Crop=1',
address: 'Little Tingewick, Buckingham',
price: '£1,250,000',
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`viewing-booking it matches a snapshot 1`] = `
.emotion-6 html,
.emotion-6 body,
.emotion-6 div,
.emotion-6 span,
.emotion-6 applet,
.emotion-6 object,
.emotion-6 iframe,
.emotion-6 h1,
.emotion-6 h2,
.emotion-6 h3,
.emotion-6 h4,
.emotion-6 h5,
.emotion-6 h6,
.emotion-6 p,
.emotion-6 blockquote,
.emotion-6 pre,
.emotion-6 a,
.emotion-6 abbr,
.emotion-6 acronym,
.emotion-6 address,
.emotion-6 big,
.emotion-6 cite,
.emotion-6 code,
.emotion-6 del,
.emotion-6 dfn,
.emotion-6 em,
.emotion-6 img,
.emotion-6 ins,
.emotion-6 kbd,
.emotion-6 q,
.emotion-6 s,
.emotion-6 samp,
.emotion-6 small,
.emotion-6 strike,
.emotion-6 strong,
.emotion-6 sub,
.emotion-6 sup,
.emotion-6 tt,
.emotion-6 var,
.emotion-6 b,
.emotion-6 u,
.emotion-6 i,
.emotion-6 center,
.emotion-6 dl,
.emotion-6 dt,
.emotion-6 dd,
.emotion-6 menu,
.emotion-6 ol,
.emotion-6 ul,
.emotion-6 li,
.emotion-6 fieldset,
.emotion-6 form,
.emotion-6 label,
.emotion-6 legend,
.emotion-6 table,
.emotion-6 caption,
.emotion-6 tbody,
.emotion-6 tfoot,
.emotion-6 thead,
.emotion-6 tr,
.emotion-6 th,
.emotion-6 td,
.emotion-6 article,
.emotion-6 aside,
.emotion-6 canvas,
.emotion-6 details,
.emotion-6 embed,
.emotion-6 figure,
.emotion-6 figcaption,
.emotion-6 footer,
.emotion-6 header,
.emotion-6 hgroup,
.emotion-6 main,
.emotion-6 menu,
.emotion-6 nav,
.emotion-6 output,
.emotion-6 ruby,
.emotion-6 section,
.emotion-6 summary,
.emotion-6 time,
.emotion-6 mark,
.emotion-6 audio,
.emotion-6 video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
.emotion-6 article,
.emotion-6 aside,
.emotion-6 details,
.emotion-6 figcaption,
.emotion-6 figure,
.emotion-6 footer,
.emotion-6 header,
.emotion-6 hgroup,
.emotion-6 main,
.emotion-6 menu,
.emotion-6 nav,
.emotion-6 section {
display: block;
}
.emotion-6 *[hidden] {
display: none;
}
.emotion-6 body {
line-height: 1;
}
.emotion-6 menu,
.emotion-6 ol,
.emotion-6 ul {
list-style: none;
}
.emotion-6 blockquote,
.emotion-6 q {
quotes: none;
}
.emotion-6 blockquote:before,
.emotion-6 blockquote:after,
.emotion-6 q:before,
.emotion-6 q:after {
content: '';
content: none;
}
.emotion-6 table {
border-collapse: collapse;
border-spacing: 0;
}
.emotion-5 {
font-size: 14px;
font-family: "Roboto",sans-serif;
background: #f9fbfd;
color: #12263f;
}
#appointment-bookings-viewing .emotion-2 {
font-family: "Open Sans",sans-serif;
font-size: 14px;
font-weight: bold;
color: #1e2554;
margin-bottom: 0.5em;
}
#appointment-bookings-viewing .emotion-1 {
font-size: 14px;
font-family: "Roboto",sans-serif;
margin-bottom: 1em;
}
#appointment-bookings-viewing .emotion-4 {
font-family: "Roboto",sans-serif;
font-size: 20px;
color: #0061a8;
border: 1px solid #0061a8;
background: #f9fbfd;
}
#appointment-bookings-viewing .emotion-4:hover {
background: #0061a8;
color: #f9fbfd;
}
#appointment-bookings-viewing .emotion-3 {
font-family: "Roboto",sans-serif;
font-size: 20px;
border: 1px solid #0061a8;
}
.emotion-0 {
background: url();
}
<body>
<div>
<button
class="viewing_booking-btn svelte-18bjhk"
>
Book a viewing
</button>
<div
class="reapit-modal-wrapper svelte-dwjkb3"
>
<div>
<div
class="reapit-modal svelte-dwjkb3"
>
<div
class="modal-close svelte-dwjkb3"
>
<i
class="modal-close-btn svelte-dwjkb3"
/>
</div>
<h3
class="modal-title svelte-dwjkb3"
title="Book a Viewing"
>
Book a Viewing
</h3>
<div
class="modal-content"
>
<form
class="emotion-5 emotion-6 svelte-18bjhk"
>
<div
class="property-image emotion-0 svelte-18bjhk"
>
<h4
class="svelte-18bjhk"
>
<strong
class="svelte-18bjhk"
>
</strong>
</h4>
</div>
<div
class="viewing-booking-email-form svelte-18bjhk"
>
<p
class="emotion-1 svelte-18bjhk"
>
To book a viewing, please enter your e-mail below.
</p>
<label
class="emotion-2 svelte-18bjhk"
for="viewing-booking-email"
>
E-mail*
</label>
<input
class="emotion-3 svelte-18bjhk"
id="viewing-booking-email"
placeholder="Your e-mail address"
type="email"
/>
</div>
<div
class="viewing-booking-form-submit svelte-18bjhk"
>
<button
class="emotion-4 svelte-18bjhk"
type="submit"
>
Get Appointments
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import ViewingBooking from '../viewing-booking.svelte'
import { render } from '@testing-library/svelte'

describe('viewing-booking', () => {
it('it matches a snapshot', () => {
const wrapper = render(ViewingBooking, {
apiKey: '',
parentSelector: '#appointment-bookings-viewing',
theme: {
baseBackgroundColor: '#f9fbfd',
basefontSize: '14px',
basefontColor: '#12263f',
inverseFontColor: '#f9fbfd',
secondaryfontColor: '#1e2554',
primaryHeadingFontSize: '24px',
secondaryHeadingFontSize: '20px',
baseFontFamily: '"Roboto", sans-serif',
headingFontFamily: '"Open Sans", sans-serif',
primaryAccentColor: '#0061a8',
secondaryAccentColor: '#1e2554',
mapAccentColor: '#7bc9eb',
breakPoints: {
mobile: '',
tablet: '',
laptop: '',
desktop: '',
},
},
})
const { container } = wrapper
expect(container).toMatchSnapshot()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<script>
import { css } from 'emotion'
import { getProperty } from '../api/property'
import { generateThemeClasses, resetCSS } from '../../../common/styles'
import { onMount, onDestroy } from 'svelte'
import Modal from '../../../common/components/modal.svelte'
import viewBookingStore from '../core/store'
import { validateEmail } from '../../../common/utils/validate'
export let theme
export let apiKey
export let parentSelector
export let submitAction
let isModalOpen = true
let isLoading
let email
let inputValue
let propertyData
let backgroundImage
let correctEmail = true
const themeClasses = generateThemeClasses(theme, parentSelector)
function handleToggleModal() {
isModalOpen = !isModalOpen
}
function handleInput({ target }) {
inputValue = target.value
viewBookingStore.update(values => ({
...values,
email: inputValue,
}))
}
function submitForm() {
correctEmail = validateEmail(email)
correctEmail && submitAction && submitAction(email)
}
const unsubscribe = viewBookingStore.subscribe(store => {
isLoading = store.isLoading
email = store.email
propertyData = store.propertyData
})
function updateImage(propertyData) {
backgroundImage = css`
background: url(${propertyData && propertyData.image});
`
}
$: updateImage(propertyData)
onMount(async () => {
isLoading = true
const propertyData = await getProperty()
viewBookingStore.update(values => ({
...values,
initializers: {
theme,
apiKey,
parentSelector,
},
themeClasses,
propertyData,
}))
isLoading = false
})
onDestroy(() => unsubscribe())
</script>

<style>
.viewing_booking-btn {
padding: 0.5em;
font-size: 1em;
}
.viewing-booking-email-form {
padding: 0.5em;
}
.viewing-booking-email-form::after {
content: '';
clear: both;
display: block;
}
.viewing-booking-email-form p {
padding: 0.5em 0;
line-height: 1em;
}
.viewing-booking-email-form label {
float: left;
padding: 0.5em 0;
line-height: 1em;
}
.viewing-booking-email-form input {
width: 70%;
float: right;
height: 2em;
border-radius: 0.25em;
outline: none;
padding: 0 0.5em;
}
.property-image {
background-size: cover;
padding: 1em;
padding-top: 62.5%;
position: relative;
}
.property-image h4 {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 0.5em;
box-sizing: border-box;
font-size: 1.1em;
background: linear-gradient(transparent, #c8c8c8);
}
.property-image h4 strong {
float: right;
font-weight: 600;
}
.viewing-booking-form-submit {
width: 100%;
padding: 0.5em 0.5em 1em;
box-sizing: border-box;
}
.viewing-booking-form-submit button {
width: 100%;
padding: 0.3em;
border-radius: 0.25em;
cursor: pointer;
}
.invaild-email {
float: right;
color: #d8000c;
font-size: 0.8em;
padding: 0.5em;
}
</style>

<button on:click={handleToggleModal} class="viewing_booking-btn">Book a viewing</button>
<Modal {isModalOpen} closeModal={handleToggleModal} {isLoading} title="Book a Viewing">

<form on:submit|preventDefault={submitForm} class="{themeClasses.globalStyles} {resetCSS}">
<div class="property-image {backgroundImage}">
<h4>
{propertyData && propertyData.address}
<strong>{propertyData && propertyData.price}</strong>
</h4>
</div>
<div class="viewing-booking-email-form">
<p class={themeClasses.bodyText}>To book a viewing, please enter your e-mail below.</p>
<label class={themeClasses.secondaryStrapline} for="viewing-booking-email">E-mail*</label>
<input
class={themeClasses.input}
type="email"
id="viewing-booking-email"
on:input={handleInput}
placeholder="Your e-mail address" />
{#if !correctEmail}
<span class="invaild-email {themeClasses.errorText}">Please enter a valid e-mail address</span>
{/if}
</div>
<div class="viewing-booking-form-submit">
<button class={themeClasses.button} type="submit">Get Appointments</button>
</div>
</form>

</Modal>
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ReactViewingWidgetComponent test match snapshot 1`] = `
Viewing_booking {
"$$": Object {
"after_update": Array [],
"before_update": Array [],
"bound": Object {},
"callbacks": Object {},
"context": Map {},
"ctx": Array [
true,
true,
Object {
"address": "",
"image": "",
"price": "",
},
"css-cb9zl5",
true,
Object {
"bodyText": "css-n0w2qa",
"button": "css-l8x1wu",
"globalStyles": "css-11c02ub",
"input": "css-1sj9ihm",
"offerBanner": "css-s4b31o",
"pagination": "css-1sys580",
"paginationActive": "css-1sys580",
"primaryHeading": "css-ayk9xy",
"primaryStrapline": "css-1d7j4w6",
"resultItem": "css-2mowv6",
"searchBox": "css-81h19r",
"secondaryHeading": "css-1qz6ie0",
"secondaryStrapline": "css-1kep8ws",
"selectedItem": "css-1w110sd",
},
[Function],
[Function],
[Function],
Object {
"baseBackgroundColor": "#f9fbfd",
"baseFontFamily": "\\"Roboto\\", sans-serif",
"basefontColor": "#12263f",
"basefontSize": "14px",
"breakPoints": Object {
"desktop": "",
"laptop": "",
"mobile": "",
"tablet": "",
},
"headingFontFamily": "\\"Open Sans\\", sans-serif",
"inverseFontColor": "#f9fbfd",
"mapAccentColor": "#7bc9eb",
"primaryAccentColor": "#0061a8",
"primaryHeadingFontSize": "24px",
"secondaryAccentColor": "#1e2554",
"secondaryHeadingFontSize": "20px",
"secondaryfontColor": "#1e2554",
},
"",
"#appointment-bookings-viewing",
undefined,
],
"dirty": Array [
-1,
],
"fragment": Object {
"c": [Function],
"d": [Function],
"i": [Function],
"l": [Function],
"m": [Function],
"o": [Function],
"p": [Function],
},
"not_equal": [Function],
"on_destroy": Array [
[Function],
],
"on_mount": Array [],
"props": Object {
"apiKey": 10,
"parentSelector": 11,
"submitAction": 12,
"theme": 9,
},
"update": [Function],
},
"$capture_state": [Function],
"$inject_state": [Function],
"$set": [Function],
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ReapitViewingBookingComponent } from '../index'

describe('ReactViewingWidgetComponent', () => {
it('test match snapshot', () => {
expect(
ReapitViewingBookingComponent({
apiKey: '',
parentSelector: '#appointment-bookings-viewing',
theme: {
baseBackgroundColor: '#f9fbfd',
basefontSize: '14px',
basefontColor: '#12263f',
inverseFontColor: '#f9fbfd',
secondaryfontColor: '#1e2554',
primaryHeadingFontSize: '24px',
secondaryHeadingFontSize: '20px',
baseFontFamily: '"Roboto", sans-serif',
headingFontFamily: '"Open Sans", sans-serif',
primaryAccentColor: '#0061a8',
secondaryAccentColor: '#1e2554',
mapAccentColor: '#7bc9eb',
breakPoints: {
mobile: '',
tablet: '',
laptop: '',
desktop: '',
},
},
}),
).toMatchSnapshot()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import viewingBookingStore from '../store'

describe('store', () => {
it('should return a default store', () => {
const expected = {
initializers: {
apiKey: '',
parentSelector: '',
theme: {},
},
email: '',
propertyData: { image: '', address: '', price: '' },
isLoading: false,
themeClasses: {
globalStyles: '',
primaryHeading: '',
secondaryHeading: '',
primaryStrapline: '',
secondaryStrapline: '',
selectedItem: '',
bodyText: '',
button: '',
input: '',
resultItem: '',
searchBox: '',
offerBanner: '',
pagination: '',
paginationActive: '',
},
}
const unsubscribe = viewingBookingStore.subscribe(store => {
expect(store).toEqual(expected)
})
unsubscribe()
})
})
27 changes: 27 additions & 0 deletions packages/web-components/src/viewing-booking/client/core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import ViewingBooking from '../components/viewing-booking.svelte'
import { InitializerTheme } from '../../../common/styles/index'

export interface PropertyData {
image: string
address: string
price: string
}
export interface ViewingBookingInitializers {
theme: Partial<InitializerTheme>
apiKey: string
parentSelector: string
}

export const ReapitViewingBookingComponent = ({ parentSelector, apiKey, theme }: ViewingBookingInitializers) =>
new ViewingBooking({
target: document.querySelector(parentSelector) || document.body,
props: {
theme,
apiKey,
parentSelector,
},
})

Object.defineProperty(window, 'ReapitViewingBookingComponent', {
value: ReapitViewingBookingComponent,
})
45 changes: 45 additions & 0 deletions packages/web-components/src/viewing-booking/client/core/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { writable, Writable } from 'svelte/store'
import { ViewingBookingInitializers, PropertyData } from './index'
import { ThemeClasses } from '../../../common/styles'

export interface ViewingBookingStore {
initializers: ViewingBookingInitializers
themeClasses: ThemeClasses

email: string
propertyData: PropertyData
isLoading: boolean
}

const viewBookingStore: Writable<ViewingBookingStore> = writable({
initializers: {
apiKey: '',
parentSelector: '',
theme: {},
},
themeClasses: {
globalStyles: '',
primaryHeading: '',
secondaryHeading: '',
primaryStrapline: '',
secondaryStrapline: '',
selectedItem: '',
bodyText: '',
button: '',
input: '',
resultItem: '',
searchBox: '',
offerBanner: '',
pagination: '',
paginationActive: '',
},
email: '',
isLoading: false,
propertyData: {
image: '',
address: '',
price: '',
},
})

export default viewBookingStore
34 changes: 34 additions & 0 deletions packages/web-components/src/viewing-booking/client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Web Components</title>
<link
href="https://fonts.googleapis.com/css?family=Montserrat|Open+Sans|Roboto|Roboto+Slab&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="./dist/viewing-booking.css" />
<style>
#appointment-bookings {
max-width: 1200px;
margin: 0 auto;
}
</style>
</head>
<body>
Book a viewing
<div id="appointment-bookings-viewing"></div>

<script src="./dist/viewing-booking.js"></script>
<script src="./themes/viewing-booking.js"></script>
<script>
if (window.ReapitViewingBookingComponent) {
new ReapitViewingBookingComponent({
theme: window.theme,
apiKey: '',
parentSelector: '#appointment-bookings-viewing',
})
}
</script>
</body>
</html>

0 comments on commit 629fb15

Please sign in to comment.