Real estate input clean up.

This commit is contained in:
Naida Vatric
2020-03-09 23:30:37 +01:00
parent 96bc66ef7b
commit 5f674230e1
10 changed files with 182 additions and 186 deletions

View File

@@ -6,16 +6,6 @@ const {
} = require("./enums"); } = require("./enums");
const BASIC_BOOLEAN_PUBLISH = [ const BASIC_BOOLEAN_PUBLISH = [
{
dbField: "balcony",
title: "Balkon",
categoriesToShow: [
AD_CATEGORY.FLAT,
AD_CATEGORY.HOUSE,
AD_CATEGORY.APARTMENT,
AD_CATEGORY.COTTAGE
]
},
{ {
dbField: "newBuilding", dbField: "newBuilding",
title: "Novogradnja", title: "Novogradnja",
@@ -28,6 +18,17 @@ const BASIC_BOOLEAN_PUBLISH = [
AD_CATEGORY.GARAGE AD_CATEGORY.GARAGE
] ]
}, },
{
dbField: "balcony",
title: "Balkon",
categoriesToShow: [
AD_CATEGORY.FLAT,
AD_CATEGORY.HOUSE,
AD_CATEGORY.APARTMENT,
AD_CATEGORY.COTTAGE
]
},
{ {
dbField: "elevator", dbField: "elevator",
title: "Lift", title: "Lift",
@@ -51,6 +52,34 @@ const BASIC_BOOLEAN_PUBLISH = [
]; ];
const BASIC_INPUT_PUBLISH = [ const BASIC_INPUT_PUBLISH = [
{
dbField: "title",
title: "Naslov",
categoriesToShow: [
AD_CATEGORY.FLAT,
AD_CATEGORY.HOUSE,
AD_CATEGORY.APARTMENT,
AD_CATEGORY.COTTAGE,
AD_CATEGORY.OFFICE,
AD_CATEGORY.LAND,
AD_CATEGORY.GARAGE
],
constraint: ["required"]
},
{
dbField: "shortDescription",
title: "Opis",
categoriesToShow: [
AD_CATEGORY.FLAT,
AD_CATEGORY.HOUSE,
AD_CATEGORY.APARTMENT,
AD_CATEGORY.COTTAGE,
AD_CATEGORY.OFFICE,
AD_CATEGORY.LAND,
AD_CATEGORY.GARAGE
],
constraint: []
},
{ {
dbField: "price", dbField: "price",
title: "Cijena (KM)", title: "Cijena (KM)",
@@ -85,6 +114,20 @@ const BASIC_INPUT_PUBLISH = [
categoriesToShow: [AD_CATEGORY.HOUSE, AD_CATEGORY.COTTAGE], categoriesToShow: [AD_CATEGORY.HOUSE, AD_CATEGORY.COTTAGE],
constraint: ["numerical"] constraint: ["numerical"]
}, },
{
dbField: "streetName",
title: "Adresa",
categoriesToShow: [
AD_CATEGORY.FLAT,
AD_CATEGORY.HOUSE,
AD_CATEGORY.APARTMENT,
AD_CATEGORY.COTTAGE,
AD_CATEGORY.OFFICE,
AD_CATEGORY.LAND,
AD_CATEGORY.GARAGE
],
constraint: []
},
{ {
dbField: "numberOfRooms", dbField: "numberOfRooms",
title: "Broj soba", title: "Broj soba",
@@ -117,48 +160,6 @@ const BASIC_INPUT_PUBLISH = [
AD_CATEGORY.OFFICE AD_CATEGORY.OFFICE
], ],
constraint: ["integer"] constraint: ["integer"]
},
{
dbField: "title",
title: "Naslov",
categoriesToShow: [
AD_CATEGORY.FLAT,
AD_CATEGORY.HOUSE,
AD_CATEGORY.APARTMENT,
AD_CATEGORY.COTTAGE,
AD_CATEGORY.OFFICE,
AD_CATEGORY.LAND,
AD_CATEGORY.GARAGE
],
constraint: ["required"]
},
{
dbField: "shortDescription",
title: "Opis",
categoriesToShow: [
AD_CATEGORY.FLAT,
AD_CATEGORY.HOUSE,
AD_CATEGORY.APARTMENT,
AD_CATEGORY.COTTAGE,
AD_CATEGORY.OFFICE,
AD_CATEGORY.LAND,
AD_CATEGORY.GARAGE
],
constraint: []
},
{
dbField: "streetName",
title: "Adresa",
categoriesToShow: [
AD_CATEGORY.FLAT,
AD_CATEGORY.HOUSE,
AD_CATEGORY.APARTMENT,
AD_CATEGORY.COTTAGE,
AD_CATEGORY.OFFICE,
AD_CATEGORY.LAND,
AD_CATEGORY.GARAGE
],
constraint: []
} }
]; ];

View File

@@ -243,6 +243,9 @@ const postPublishInputs = async (req, res) => {
//Contact email saved in other table //Contact email saved in other table
const contactEmail = req.body.email || ""; const contactEmail = req.body.email || "";
const imageUrlsArray = req.body.imageUrls || [];
console.log(imageUrlsArray);
realEstate.balcony = balcony; realEstate.balcony = balcony;
realEstate.elevator = elevator; realEstate.elevator = elevator;
realEstate.newBuilding = newBuilding; realEstate.newBuilding = newBuilding;

View File

@@ -164,7 +164,6 @@ h3 {
} }
.custom-col { .custom-col {
width: 18%;
margin-left: auto; margin-left: auto;
left: auto; left: auto;
right: auto; right: auto;
@@ -175,7 +174,16 @@ h3 {
border-radius: 10px; border-radius: 10px;
border: 4px dashed #02adba; border: 4px dashed #02adba;
border-image: none; border-image: none;
max-width: 500px; max-width: 100%;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
.dz-progress {
/* progress bar covers file name */
display: none;
}
h3.custom-h3 {
font-size: 20px;
}

View File

@@ -1,7 +1,7 @@
<br> <br>
<div class="row"> <div class="row">
<% for (const input of additionalInputInputs){ %> <% for (const input of additionalInputInputs){ %>
<div class="input-field col s3 m4 l5"> <div class="input-field col s12">
<textarea <textarea
id="<%= input.dbField %>" id="<%= input.dbField %>"
form="publishForm" form="publishForm"
@@ -15,9 +15,9 @@
</div> </div>
<br> <br>
<div class="col s12">
<% for (const input of additionalBooleanPublishInputs){ %> <% for (const input of additionalBooleanPublishInputs){ %>
<p> <p class="col s3">
<label class="checkbox-label"> <label class="checkbox-label">
<input type="checkbox" class="filled-in" name="<%= input.dbField %>" <input type="checkbox" class="filled-in" name="<%= input.dbField %>"
<% if (additionalBooleanPublishValues[input.dbField]) { %> <% if (additionalBooleanPublishValues[input.dbField]) { %>
@@ -27,10 +27,13 @@
</label> </label>
</p> </p>
<% } %> <% } %>
</div>
<br>
<br>
<br> <br>
<% for (const input of additionalSegmentSelectInputs){ %> <% for (const input of additionalSegmentSelectInputs){ %>
<div> <div>
<br>
<label class="checkbox-label"><%= input.title %>: </label><br><br> <label class="checkbox-label"><%= input.title %>: </label><br><br>
<span class="segmented small"> <span class="segmented small">
<% for (const segmentObject of input.values) { %> <% for (const segmentObject of input.values) { %>

View File

@@ -13,9 +13,9 @@
<% } %> <% } %>
</div> </div>
<br> <br>
<div class="row"> <div class="col s12">
<% for (const input of basicBooleanPublishInputs){ %> <% for (const input of basicBooleanPublishInputs){ %>
<p> <p class="col s3">
<label class="checkbox-label"> <label class="checkbox-label">
<input type="checkbox" class="filled-in" name="<%= input.dbField %>" <input type="checkbox" class="filled-in" name="<%= input.dbField %>"
<% if (basicBooleanPublishValues[input.dbField]) { %> <% if (basicBooleanPublishValues[input.dbField]) { %>

View File

@@ -4,15 +4,16 @@
Unesite kontakt email i objavite oglas. Unesite kontakt email i objavite oglas.
<br> <br>
<div class="row center-align input-field col s3 m4 l5 form-group">
<input <div class="row center-align">
id="email" <div class="col">
name="email" <input id="email" name="email" type="email" placeholder="vas.email@mail.com" required size="250" />
type="email" </div>
> </div>
<div class="messages"></div> <div class="col">
<label for="email">Email</label> <h6 id="error-label-email" style="color: red"> </h6>
</div> </div>
</div> </div>
<br> <br>
<div class="row center-align"> <div class="row center-align">

View File

@@ -1,7 +1,8 @@
<div class="row center-align"> <div class="row center-align">
<h3> <h3 class="custom-h3">
Izaberite lokaciju nekretnine na mapi. Izaberite lokaciju nekretnine na mapi.
</h3> </h3>
<span>(Kliknite ili prevucite oznaku.)</span>
</div> </div>
<div class="row center-align"> <div class="row center-align">

View File

@@ -1,111 +1,12 @@
<br> <br>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--file"> <br>
<input type="file" id="selector">
</div>
<input class="mdl-button mdl-button--raised mdl-button--colored" type="button" value="Upload"
onclick="generateSignedURL()">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--file" id="status"></div>
<s>******************************</s>
<div action="/photos-upload" class="dropzone" id="photos-upload"> <div action="/photos-upload" class="dropzone" id="photos-upload">
<div class="fallback"> <div class="fallback">
<input name="file" type="file" multiple /> <input name="file" type="file" multiple />
</div> </div>
</div> </div>
<button id="test">TEST</button>
<input type="hidden" name="imageUrls" id="imageUrls" value="">
<script type="text/javascript">
$(document).ready(function(){
// Manual dropzone init
const dropzoneOptions = {
url: "/photos-upload", //can be a function that returns url ?
autoProcessQueue:false, //not to upload files automaticly
method: "put", //or post
parallelUploads: 1,
uploadMultiple: false, //or true ??
addRemoveLinks: true,
maxFilesize: 2, //MB,
resizeWidth: 600,
maxFiles: 10, // ??
acceptedFiles: "image/*",
accept: function(file, done){
console.log('test');
},
dictDefaultMessage: `<span class="text-center">
<h3>Prevuci fotografije ili klikni za dodavanje!</h3>
</span>`,
dictResponseError: 'Error uploading file!',
dictRemoveFile: 'Izbriši '
};
var photosUploader = new Dropzone('#photos-upload', dropzoneOptions);
$("#test").click(function(e){ <input type="hidden" name="imageUrls" id="imageUrls">
e.preventDefault();
const addedFiles = photosUploader.files.filter(file => file.status==="added");
addedFiles.forEach( file => {
generateSignedURL(file);
})
});
});
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
function getFileName(fileName) {
const encodedFileName = (uuidv4() + fileName).replace(/\s+/g, '');
return encodedFileName;
}
function upload() {
var file = $('#selector')[0].files[0];
uploadFile(file)
}
async function generateSignedURL(file) {
const fileName = getFileName(file.name);
const response = await fetch('/generateSignedURL?filename=' + fileName);
if (!response.ok) {
throw new Error('Network response for fetch was not ok.');
}
let signedUrl = await response.text();
signedUrl = signedUrl.replace(/\"/g, "")
// console.log("Got signedURL: " + c)
// console.log("Trying to upload " + fileName)
uploadFile(file, fileName, signedUrl);
// console.log("Complete")
return false;
}
function uploadFile(file, fileName, url) {
$("#status").html('Starting Upload...')
fetch(url, {
method: 'PUT',
headers: new Headers({'content-type': 'image/*'}),
mode: 'cors',
body: file
})
.then(response => response.text())
.then (response => {
return response;
}
)
.catch(error => $("#status").html(error)
)
.then(response => {
$("#status").html('File uploaded successfully: ' + fileName )
$("#imageUrls").val($("#imageUrls").val()+ fileName+"|");
});
}
</script>

View File

@@ -36,6 +36,8 @@
$(document).ready(function(){ $(document).ready(function(){
$('.tabs').tabs(); $('.tabs').tabs();
//VALIDATION
//Helper validation functions //Helper validation functions
const isValidEmail = $email => { const isValidEmail = $email => {
const simpleEmailRegex = /^(([^<>()\[\]\\.,;:\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,}))$/; const simpleEmailRegex = /^(([^<>()\[\]\\.,;:\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,}))$/;
@@ -151,9 +153,86 @@
} }
} }
//FILE UPLOADS
// Manual dropzone init
const dropzoneOptions = {
url: "/photos-upload", //not used
autoProcessQueue:false, //not to upload files automaticly
method: "put",
parallelUploads: 1,
addRemoveLinks: true,
maxFilesize: 2, //MB,
resizeWidth: 600,
maxFiles: 10,
init: function() {
this.on("addedfile", function(event) {
while (this.files.length > this.options.maxFiles) { //removes to many files
this.removeFile(this.files[0]);
}
});
},
acceptedFiles: "image/*",
dictDefaultMessage: `<span class="text-center">
<h3 class="custom-h3">Prevuci fotografije ili klikni za dodavanje!</h3>
(Maksimalno 10 fotografija.)
</span>`,
dictResponseError: 'Greska pri uploadu fajla!',
dictRemoveFile: 'Ukloni',
dictFileTooBig: `Fajl mora biti manji od 2 MB!`,
dictInvalidFileType: 'Izabrani fajl mora biti fotografija!'
};
const photosUploader = new Dropzone('#photos-upload', dropzoneOptions);
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
function getFileName(fileName) {
const encodedFileName = (uuidv4() + fileName).replace(/\s+/g, '');
return encodedFileName;
}
async function generateSignedURL(file) {
const fileName = getFileName(file.name);
const response = await fetch('/generateSignedURL?filename=' + fileName);
if (!response.ok) {
throw new Error('Network response for fetch was not ok.');
}
let signedUrl = await response.text();
signedUrl = signedUrl.replace(/\"/g, "")
uploadFile(file, fileName, signedUrl);
return true;
}
function uploadFile(file, fileName, url) {
fetch(url, {
method: 'PUT',
headers: new Headers({'content-type': 'image/*'}),
mode: 'cors',
body: file
})
.then(response => response.text())
.then (response => {
return response;
}
)
.catch(error => console.error(error)
)
.then(response => {
$("#imageUrls").val($("#imageUrls").val()+ fileName+"|");
});
}
$("#submit").click( function () { $("#submit").click( function () {
//SET LOCATION DATA
if (marker) { if (marker) {
const currentLocation = marker.getPosition(); const currentLocation = marker.getPosition();
@@ -170,16 +249,20 @@
$("#lng").val(0); $("#lng").val(0);
} }
//UPLOAD IMAGE FILES
const addedFiles = photosUploader.files.filter(file => file.status!=="error");
addedFiles.forEach( file => {
generateSignedURL(file);
})
//SHOW ERRORS
//Tag for checking of error presence //Tag for checking of error presence
let hasErrors = false; let hasErrors = false;
//Check if email is valid //Check if email is valid
const validEmail = isValidEmail($("#email").val()); const validEmail = isValidEmail($("#email").val());
//Show messeges for invalid email is present //Show messeges for invalid email is present
if (!validEmail) { if (!validEmail) {
const errorMsgs = ["Unesite validan email."]; $("#error-label-email").text("Greška ! Unešeni email nije validan");
const email = document.querySelector("#email");
showErrorsForInput( email, errorMsgs)
hasErrors = true; hasErrors = true;
}; };
//Check if other input fields are valid - vratiti se na ovo!! //Check if other input fields are valid - vratiti se na ovo!!

View File

@@ -58,33 +58,28 @@ setInterval(crawl, CRAWLER_INTERVAL * 1000);
setInterval(checkUpNotify, 1000 * 60 * 60 * 24); setInterval(checkUpNotify, 1000 * 60 * 60 * 24);
//Google storage req //Google storage req
const PROJECT_ID = "marketalarm";
const KEY_FILENAME = ""; //relative path
const BUCKET_NAME = "marketalarm-photos"; const BUCKET_NAME = "marketalarm-photos";
//Tried implicitly creating with env credentials and direktcly as here
const storage = new Storage(); const storage = new Storage();
const bucket = storage.bucket(BUCKET_NAME); const bucket = storage.bucket(BUCKET_NAME);
app.get("/generateSignedURL", (req, res) => { app.get("/generateSignedURL", (req, res) => {
async function generateSignedUrl() { async function generateSignedUrl() {
console.log("Started server function!"); // console.log("Started server function!");
const options = { const options = {
//Tried to define Google ID and private key while debugging version: "v2",
version: "v2", //tried v4 also
action: "write", action: "write",
contentType: "image/*", //tried without and with specific image/png ex. contentType: "image/*",
expires: Date.now() + 86400000 expires: Date.now() + 86400000
}; };
const filename = req.query.filename; const filename = req.query.filename;
console.log("Filename: ", filename); //console.log("Filename: ", filename);
console.log("Bucket name:", bucket.name); // console.log("Bucket name:", bucket.name);
const [url] = await bucket.file(filename).getSignedUrl(options); const [url] = await bucket.file(filename).getSignedUrl(options);
console.log(`The signed url is ${url}.`); //console.log(`The signed url is ${url}.`);
res.status(200).send(url); res.status(200).send(url);
} }