Contact form UI
This commit is contained in:
69
web/dist/main.css
vendored
69
web/dist/main.css
vendored
@@ -757,7 +757,8 @@ html {
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
.ld-check-availability button {
|
||||
.ld-check-availability button,
|
||||
.contact-form button {
|
||||
font-size: 18px;
|
||||
padding: 15px 0;
|
||||
background-color: #51bc6a;
|
||||
@@ -858,7 +859,7 @@ h5 {
|
||||
|
||||
.modal h3 {
|
||||
color: #575a60;
|
||||
font-size: 16px;
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
letter-spacing: .3px;
|
||||
}
|
||||
@@ -875,6 +876,66 @@ h5 {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.close:hover {
|
||||
/*background: #00d9ff;*/
|
||||
.contact-form input, textarea {
|
||||
padding: 10px;
|
||||
border: 1px solid #e2e2e6;
|
||||
width: 420px;
|
||||
border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
font-size: 14px;
|
||||
color: #212126;
|
||||
letter-spacing: .2px;
|
||||
}
|
||||
|
||||
.contact-form-email-phone input {
|
||||
}
|
||||
|
||||
.contact-form-email-phone input:first-child {
|
||||
margin-right: 5px;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.contact-form-email-phone input:last-child {
|
||||
margin-left: 5px;
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.contact-form-name,
|
||||
.contact-form-message,
|
||||
.contact-form-email-phone {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.contact-form-footer {
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.contact-form-alert input {
|
||||
width: 15px;
|
||||
}
|
||||
|
||||
.contact-form-alert span {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.contact-form-alert {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.noselect {
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-khtml-user-select: none; /* Konqueror HTML */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||
user-select: none; /* Non-prefixed version, currently
|
||||
supported by Chrome and Opera */
|
||||
}
|
||||
|
||||
input.validation-failed {
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
@@ -1,30 +1,124 @@
|
||||
import React from 'react';
|
||||
import React from 'react'
|
||||
|
||||
export default class ContactModal extends React.Component {
|
||||
onContactCloseClick () {
|
||||
|
||||
}
|
||||
|
||||
onContactCloseClick (e) {
|
||||
e.preventDefault()
|
||||
|
||||
this.props.dispatch({
|
||||
type: 'CLOSE_CONTACT'
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
})
|
||||
}
|
||||
|
||||
onSubmit (e) {
|
||||
e.preventDefault()
|
||||
const {name, email} = this.props.contact;
|
||||
|
||||
if (!name || !email) {
|
||||
this.props.dispatch({
|
||||
type: 'INVALID_CONTACT'
|
||||
})
|
||||
} else {
|
||||
this.props.dispatch({
|
||||
type: 'SUBMIT_CONTACT'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onFieldChange (field, e) {
|
||||
this.props.dispatch({
|
||||
type: 'UPDATE_CONTACT_INFO',
|
||||
action: {
|
||||
field,
|
||||
value: e.target.value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onAlertToggle (e) {
|
||||
const alert = this.props.contact.alert
|
||||
this.props.dispatch({
|
||||
type: 'UPDATE_CONTACT_INFO',
|
||||
action: {
|
||||
field: 'alert',
|
||||
value: !alert
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
message,
|
||||
email,
|
||||
phone,
|
||||
name,
|
||||
alert: doAlert,
|
||||
nameInvalid,
|
||||
emailInvalid
|
||||
} = this.props.contact
|
||||
|
||||
const nameValidationClass = nameInvalid ? 'validation-failed' : ''
|
||||
const emailValidationClass = emailInvalid ? 'validation-failed' : ''
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="modal">
|
||||
|
||||
<div className="modal contact-form">
|
||||
<div>
|
||||
<a href="#close" title="Zatvori" className="close" onClick={this.onContactCloseClick.bind(this)}>
|
||||
<i className="fa fa-times" aria-hidden="true"></i>
|
||||
<a
|
||||
href="#close"
|
||||
title="Zatvori"
|
||||
className="close"
|
||||
onClick={this.onContactCloseClick.bind(this)}
|
||||
>
|
||||
<i className="fa fa-times" aria-hidden="true" />
|
||||
</a>
|
||||
<h3>Kontaktirajte prodavca</h3>
|
||||
<form onSubmit={this.onSubmit.bind(this)}>
|
||||
<h3>Kontaktirajte prodavca</h3>
|
||||
<div className="contact-form-name">
|
||||
<input
|
||||
value={name}
|
||||
className={nameValidationClass}
|
||||
onChange={this.onFieldChange.bind(this, 'name')}
|
||||
placeholder="Ime i prezime"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div className="contact-form-email-phone">
|
||||
<input
|
||||
value={email}
|
||||
className={emailValidationClass}
|
||||
onChange={this.onFieldChange.bind(this, 'email')}
|
||||
placeholder="Email adresa"
|
||||
type="text"
|
||||
/>
|
||||
<input
|
||||
value={phone}
|
||||
onChange={this.onFieldChange.bind(this, 'phone')}
|
||||
placeholder="Telefon (opcionalno)"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div className="contact-form-message">
|
||||
<textarea
|
||||
onChange={this.onFieldChange.bind(this, 'message')}
|
||||
value={message}
|
||||
rows="14"
|
||||
/>
|
||||
</div>
|
||||
<div className="contact-form-alert noselect">
|
||||
<input
|
||||
type="checkbox"
|
||||
onChange={this.onAlertToggle.bind(this)}
|
||||
checked={doAlert}
|
||||
/>
|
||||
<span onClick={this.onAlertToggle.bind(this)}>
|
||||
Obavjesti me ukoliko se slična nekretnine pojavi
|
||||
</span>
|
||||
</div>
|
||||
<div className="contact-form-footer">
|
||||
<button>Pošalji poruku</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +116,9 @@ export default class ListingDetails extends React.Component {
|
||||
<div className="ld-footer" />
|
||||
</div>
|
||||
|
||||
{contactFormOpen ? <ContactModal dispatch={this.props.dispatch} /> : null}
|
||||
{contactFormOpen ? <ContactModal
|
||||
contact={this.props.contact}
|
||||
dispatch={this.props.dispatch} /> : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,13 @@ class Main extends React.Component {
|
||||
filters: {
|
||||
rooms: {},
|
||||
category: {}
|
||||
},
|
||||
contact: {
|
||||
message: '',
|
||||
name: '',
|
||||
email: '',
|
||||
phone: '',
|
||||
valid: true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,6 +523,7 @@ class Main extends React.Component {
|
||||
children.push(
|
||||
<ListingDetails
|
||||
contactFormOpen={this.state.contactFormOpen}
|
||||
contact={this.state.contact}
|
||||
listing={listing}
|
||||
imageIndex={this.state.imageIndex}
|
||||
dispatch={this.dispatch.bind(this)}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {markSeen} from './api'
|
||||
import {defaultContactMessage, listingUrl} from './helpers'
|
||||
|
||||
const setMaxPrice = ({type, action}, component) => {
|
||||
const maxPrice = parseFloat(action.maxPrice)
|
||||
@@ -52,8 +53,6 @@ const viewListingDetails = ({type, action}, component) => {
|
||||
const scrollElem = document.querySelector('.right-content')
|
||||
component.savedScrollTop = scrollElem.scrollTop
|
||||
|
||||
//component.router.listingId = action.id;
|
||||
|
||||
component.setState(
|
||||
{
|
||||
listingDetails: true,
|
||||
@@ -63,7 +62,6 @@ const viewListingDetails = ({type, action}, component) => {
|
||||
listing: action.listing
|
||||
},
|
||||
() => {
|
||||
//component.router.update();
|
||||
markSeen(action.id)
|
||||
const m = component.findMarker(action.id)
|
||||
if (m) {
|
||||
@@ -221,8 +219,6 @@ const backToResults = ({type, action}, component) => {
|
||||
listingDetails: false
|
||||
},
|
||||
() => {
|
||||
//component.router.update();
|
||||
|
||||
if (prevSelected) {
|
||||
prevSelected.marker.setIcon(component.visitedMarkerIcon())
|
||||
}
|
||||
@@ -268,7 +264,6 @@ const sortChange = ({type, action}, component) => {
|
||||
page: 0
|
||||
},
|
||||
() => {
|
||||
//component.router.update();
|
||||
component.refreshListings()
|
||||
}
|
||||
)
|
||||
@@ -280,14 +275,59 @@ const updateRoute = ({type, action}, component) => {
|
||||
|
||||
const openContact = ({type, action}, component) => {
|
||||
component.setState({
|
||||
contactFormOpen: true
|
||||
});
|
||||
contactFormOpen: true,
|
||||
contact: {
|
||||
...component.state.contact,
|
||||
message: defaultContactMessage(listingUrl(component.state.listingId)),
|
||||
emailInvalid: false,
|
||||
nameInvalid: false,
|
||||
name: '',
|
||||
email: '',
|
||||
phone: ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const closeContact = ({type, action}, component) => {
|
||||
component.setState({
|
||||
contactFormOpen: false
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
const updateContactInfo = ({type, action}, component) => {
|
||||
|
||||
let nameInvalid = component.state.contact.nameInvalid
|
||||
let emailInvalid = component.state.contact.emailInvalid
|
||||
|
||||
if (action.field === 'name') {
|
||||
nameInvalid = !action.value
|
||||
}
|
||||
|
||||
if (action.field === 'email') {
|
||||
emailInvalid = !action.value
|
||||
}
|
||||
|
||||
component.setState({
|
||||
contact: {
|
||||
...component.state.contact,
|
||||
[action.field]: action.value,
|
||||
...{nameInvalid, emailInvalid}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const invalidContact = ({type, action}, component) => {
|
||||
const {name, email} = component.state.contact
|
||||
|
||||
component.setState({
|
||||
contact: {
|
||||
...component.state.contact,
|
||||
...{nameInvalid: !name, emailInvalid: !email}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const submitContact = ({type, action}, component) => {
|
||||
}
|
||||
|
||||
const handlers = {
|
||||
@@ -313,7 +353,10 @@ const handlers = {
|
||||
SORT_CHANGE: sortChange,
|
||||
UPDATE_ROUTE: updateRoute,
|
||||
OPEN_CONTACT: openContact,
|
||||
CLOSE_CONTACT: closeContact
|
||||
CLOSE_CONTACT: closeContact,
|
||||
UPDATE_CONTACT_INFO: updateContactInfo,
|
||||
SUBMIT_CONTACT: submitContact,
|
||||
INVALID_CONTACT: invalidContact
|
||||
}
|
||||
|
||||
export const handleMessage = ({type, action}, component) => {
|
||||
@@ -321,6 +364,6 @@ export const handleMessage = ({type, action}, component) => {
|
||||
throw new `Unhandled message: ${type}`()
|
||||
}
|
||||
|
||||
console.log(type);
|
||||
console.log(type, action);
|
||||
return handlers[type]({type, action}, component)
|
||||
}
|
||||
|
||||
@@ -18,3 +18,21 @@ export const galleryImageUrl = img =>
|
||||
|
||||
export const listingImageUrl = img =>
|
||||
img && img.replace('upload/', 'upload/w_205/')
|
||||
|
||||
export const defaultContactMessage = (url) => {
|
||||
return `Pozdrav,
|
||||
|
||||
Našao/Našla sam vaš oglas na portalu Kivi za sljedeću nekretninu:
|
||||
|
||||
${url}
|
||||
|
||||
Želim da me kontaktirate kako bih dobio/dobila više informacija.
|
||||
|
||||
S poštovanjem
|
||||
`
|
||||
}
|
||||
|
||||
export const listingUrl = (id) => {
|
||||
// TODO: fix this once removing hardcoded values
|
||||
return `http://localhost:8080/?listingId=${id}`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user