initial commit: migrated from FossilSCM to git
parent
0e9635541c
commit
7a0962831b
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "server/bitser"]
|
||||||
|
path = server/bitser
|
||||||
|
url = https://github.com/gvx/bitser.git
|
@ -0,0 +1,18 @@
|
|||||||
|
var AboutUs = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
return m('.about-us', [
|
||||||
|
m('h1.text-center', "About Us"),
|
||||||
|
m('p', "Welcome to Piazza Optical, your number one source for all your optical needs. From frames and lenses to lab equipment and accessories, we are here to provide you with all these supplies while giving you personalized attention and customer service. We're dedicated to making available products that rank the very best in the latest trends in frames and sunglasses, with a focus on quality of materials and craftsmanship at the lowest cost to aid you and your store/practice in achieving the most profits."),
|
||||||
|
m('p', "Founded in 1995, Piazza Optical has come a long way from its beginnings in a tiny office in North Miami, FL. When we first started out, our passion for fashion forward frames became an obsession and drove us to scour the best factories of the world in our industry, and gave us the pillars to become a leader in the optical supplies business without losing the personal touch, highlighting honesty and integrity which sets us apart from the competition far and near. Such is the base of our company, and our honesty towards and respect for our customers is what keeps our worldwide following at the top after all these years."),
|
||||||
|
m('p', "We hope you enjoy our products as much as we enjoy offering them to you. If you have any questions or comments, please don't hesitate to contact us!"),
|
||||||
|
m('.divider',''),
|
||||||
|
m('p', "Bienvenidos a Piazza Optical la principal distribuidora de armazones ópticas, lentes oftálmicas y equipos de consultorio y de laboratorio. Estamos aquí para proveer a ópticas, distribuidores y oftalmólogos muchos de los artículos relacionados con su establecimiento, brindando a cada cliente atención personalizada y servicio al cliente. Estamos dedicados a poner a su disposición artículos ópticos de la más alta gama en las últimas tendencias de la moda en armazones y gafas de sol, poniendo especial enfoque en la calidad de materiales y mano de obra al menor costo para promover mayores ganancias para Ud. y su óptica."),
|
||||||
|
m('p', "Fundada en 1995, Piazza Optical ha logrado una larga trayectoria desde nuestros comienzos en aquella modesta oficina en North Miami, FL. Desde el principio, nuestra pasión por la moda en óptica se tornó en una obsesión y nos impulsó a buscar y establecer una firme relación con las mejores fábricas de la industria, lo cual es el pilar para convertirnos en líderes en el ramo sin por ello perder el toque personal, permitiendonos brillar en honestidad e integridad que nos diferencia de la competencia lejana y cercana. Tal es la base de nuestra empresa, ya que nuestra honestidad y respeto por nuestros clientes es lo que hace que éstos se mantengan fieles a nuestra compañía despues de tantos años."),
|
||||||
|
m('p', "Deseamos que disfruten de nuestros productos de la misma manera que nosotros disfrutamos ponerlos a vuestra disposición. Si tienen algún comentario o pregunta, por favor no duden en contactarnos!")
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AboutUs;
|
@ -0,0 +1,15 @@
|
|||||||
|
import ItemBrowser from './ItemBrowser.js';
|
||||||
|
import _Accessories from './_Accessories.js';
|
||||||
|
|
||||||
|
var Accessories = function(){
|
||||||
|
return {
|
||||||
|
view: function(){
|
||||||
|
return m('.equipment', [
|
||||||
|
m('h1.text-center','Accessories'),
|
||||||
|
m(ItemBrowser, {items: _Accessories.items})
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Accessories;
|
@ -0,0 +1,170 @@
|
|||||||
|
import _AccountApplication from "./_AccountApplication.js";
|
||||||
|
|
||||||
|
var AccountApplicationBox = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
return m('.account-application.form-horizontal', [
|
||||||
|
m('h1.text-center', 'Account Application Form'),
|
||||||
|
m('h3', 'Account Information'),
|
||||||
|
m('.form-group', [
|
||||||
|
m('.col-3', [
|
||||||
|
m('label.form-label', [
|
||||||
|
'Username',
|
||||||
|
m('small', '(use your email address)')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('col-9', [
|
||||||
|
m('input[type=text]', {
|
||||||
|
onchange: function(e){ _AccountApplication.username = e.target.value; },
|
||||||
|
value: _AccountApplication.username
|
||||||
|
})
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('h3', 'Personal Information'),
|
||||||
|
m('.form-group', [
|
||||||
|
m('.col-3', [
|
||||||
|
m('label.form-label', 'Salutation')
|
||||||
|
]),
|
||||||
|
m('.col-9', [
|
||||||
|
_AccountApplication.salutations.map(function(s){
|
||||||
|
return [
|
||||||
|
m('label.form-radio.form-inline', [
|
||||||
|
m('input[type=radio][name=salutation]', {
|
||||||
|
onchange: function(e){ _AccountApplication.salutation = e.target.value; },
|
||||||
|
value: s.value
|
||||||
|
}),
|
||||||
|
m('i.form-icon',''),
|
||||||
|
s.text
|
||||||
|
])
|
||||||
|
];
|
||||||
|
})
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('.form-group', [
|
||||||
|
m('.col-3', [
|
||||||
|
m('label.form-label', 'First Name')
|
||||||
|
]),
|
||||||
|
m('.col-9', [
|
||||||
|
m('input[type=text][placeholder=First Name]', {
|
||||||
|
onchange: function(e){ _AccountApplication.firstname = e.target.value; },
|
||||||
|
value: _AccountApplication.firstname
|
||||||
|
})
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('.form-group', [
|
||||||
|
m('.col-3', [
|
||||||
|
m('label.form-label', 'Last Name')
|
||||||
|
]),
|
||||||
|
m('.col-9', [
|
||||||
|
m('input[type=text][placeholder=Last Name]', {
|
||||||
|
onchange: function(e){ _AccountApplication.lastname = e.target.value; },
|
||||||
|
value: _AccountApplication.lastname
|
||||||
|
})
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('.form-group', [
|
||||||
|
m('.col-3', [
|
||||||
|
m('label.form-label', 'Position in Company')
|
||||||
|
]),
|
||||||
|
m('.col-9', _AccountApplication.positions.map(function(s){
|
||||||
|
return [
|
||||||
|
m('label.form-radio.form-inline', [
|
||||||
|
m('input[type=radio][name=position]', {
|
||||||
|
onchange: function(e){ _AccountApplication.position = e.target.value; },
|
||||||
|
value: s.value
|
||||||
|
}),
|
||||||
|
m('i.form-icon',''),
|
||||||
|
s.text
|
||||||
|
])
|
||||||
|
];
|
||||||
|
})
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
m('h3', 'Business Information'),
|
||||||
|
m('.form-group', [
|
||||||
|
m('.col-3', [
|
||||||
|
m('label.form-label', 'Name of Business')
|
||||||
|
]),
|
||||||
|
m('.col-9', [
|
||||||
|
m('input[type=text][placeholder=Name of Business (your shop/clinic/practice name)]', {
|
||||||
|
onchange: function(e){ _AccountApplication.store = e.target.value; },
|
||||||
|
value: _AccountApplication.store
|
||||||
|
})
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('.form-group', [
|
||||||
|
m('.col-3', [
|
||||||
|
m('label.form-label', [
|
||||||
|
'Address',
|
||||||
|
m('small', '(full address including city and country)')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('.col-9', [
|
||||||
|
m('input[type=text][placeholder=Address (full address including city and country)]', {
|
||||||
|
onchange: function(e){ _AccountApplication.address = e.target.value; },
|
||||||
|
value: _AccountApplication.address
|
||||||
|
})
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('.form-group', [
|
||||||
|
m('.col-3', [
|
||||||
|
m('label.form-label', 'Type of Business')
|
||||||
|
]),
|
||||||
|
m('.col-9', [
|
||||||
|
_AccountApplication.practice_types.map(function(s){
|
||||||
|
return [
|
||||||
|
m('label.form-radio.form-inline', [
|
||||||
|
m('input[type=radio][name=practice_type].practice-type', {
|
||||||
|
onchange: function(e){ _AccountApplication.practice_type = e.target.value; },
|
||||||
|
value: s.value
|
||||||
|
}),
|
||||||
|
m('i.form-icon', ''),
|
||||||
|
s.text
|
||||||
|
])
|
||||||
|
];
|
||||||
|
})
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('.form-group', [
|
||||||
|
m('.col-3', [
|
||||||
|
m('label.form-label', 'Phone (Office)')
|
||||||
|
]),
|
||||||
|
m('.col-9', [
|
||||||
|
m('input[type=text][placeholder=Phone (Office)]', {
|
||||||
|
onchange: function(e){ _AccountApplication.phone_office = e.target.value; },
|
||||||
|
value: _AccountApplication.phone_office
|
||||||
|
})
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('.form-group', [
|
||||||
|
m('.col-3', [
|
||||||
|
m('label.form-label', 'Phone (Cell/WhatsApp)')
|
||||||
|
]),
|
||||||
|
m('.col-9', [
|
||||||
|
m('input[type=text][placeholder=Phone (Cell/WhatsApp)]', {
|
||||||
|
onchange: function(e){ _AccountApplication.phone_cell = e.target.value; },
|
||||||
|
value: _AccountApplication.phone_cell
|
||||||
|
})
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('.form-group', [
|
||||||
|
m('.col-3', [
|
||||||
|
m('label.form-label', 'Email Address')
|
||||||
|
]),
|
||||||
|
m('.col-9', [
|
||||||
|
m('input[type=text][placeholder=Email Address].email', {
|
||||||
|
onchange: function(e){ _AccountApplication.email = e.target.value; },
|
||||||
|
value: _AccountApplication.email
|
||||||
|
})
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('button.btn.btn-primary.application-submit-button', {onclick: function(e){
|
||||||
|
e.preventDefault(); // this is require since the button is in a form
|
||||||
|
_AccountApplication.submit();
|
||||||
|
}}, "Submit")
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AccountApplicationBox;
|
@ -0,0 +1,46 @@
|
|||||||
|
import OpenOrders from './OpenOrders.js';
|
||||||
|
import ApplicationManager from './ApplicationManager.js';
|
||||||
|
import ItemImageUploader from './ItemImageUploader.js';
|
||||||
|
import FrameAdmin from './FrameAdmin.js';
|
||||||
|
import _Admin from './_Admin.js';
|
||||||
|
//import _Image from './_Image.js';
|
||||||
|
|
||||||
|
var c = function(page){
|
||||||
|
return (_Admin.page === page ? '.active' : '')
|
||||||
|
}
|
||||||
|
|
||||||
|
var Admin = function(){
|
||||||
|
var image;
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
return m('.admin',[
|
||||||
|
m('h1.text-center','Admin'),
|
||||||
|
m('ul.tab.tab-block.c-hand', [
|
||||||
|
m('li.tab-item'+c(OpenOrders), {
|
||||||
|
onclick: function(){ _Admin.page = OpenOrders; }
|
||||||
|
}, [
|
||||||
|
m('a', 'Orders')
|
||||||
|
]),
|
||||||
|
m('li.tab-item'+c(ApplicationManager), {
|
||||||
|
onclick: function(){ _Admin.page = ApplicationManager; }
|
||||||
|
}, [
|
||||||
|
m('a', 'Account Applications')
|
||||||
|
]),
|
||||||
|
m('li.tab-item'+c(FrameAdmin), {
|
||||||
|
onclick: function(){ _Admin.page = FrameAdmin; }
|
||||||
|
}, [
|
||||||
|
m('a', 'Frames')
|
||||||
|
]),
|
||||||
|
m('li.tab-item'+c(ItemImageUploader), {
|
||||||
|
onclick: function(){ _Admin.page = ItemImageUploader; }
|
||||||
|
}, [
|
||||||
|
m('a', 'Image Upload')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m(_Admin.page)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Admin;
|
@ -0,0 +1,30 @@
|
|||||||
|
import _Admin from './_Admin.js';
|
||||||
|
|
||||||
|
function ApplicationManager(ivnode){
|
||||||
|
return { view: function(vnode){
|
||||||
|
return m('.application-manager',[
|
||||||
|
m('h2', 'Open Applications'),
|
||||||
|
m('button.btn.refresh-application-button',{onclick: function(){
|
||||||
|
_Admin.getOpenApplications();
|
||||||
|
}},[m('i.icon.icon-refresh'), 'Refresh']),
|
||||||
|
m('ul.open-application-list', _Admin.open_applications.map(function(a){
|
||||||
|
return m('li', [
|
||||||
|
m('.name', a.salutation+' '+a.firstname+' '+a.lastname+ '('+a.position+' @ '+a.store+')'),
|
||||||
|
m('.info', a.practice_type+' (Office: '+a.phone_office+', Cell: '+a.phone_cell+', Email: '+a.email+')'),
|
||||||
|
m('.address', a.address),
|
||||||
|
m('input[type=text][placeholder=Password].application',{
|
||||||
|
onchange: function(e){ a.password = e.target.value },
|
||||||
|
value: a.password
|
||||||
|
}),
|
||||||
|
m('button.btn.btn-success.accept-application-button', {onclick: function(){
|
||||||
|
_Admin.acceptApplication(a);
|
||||||
|
}}, 'Accept'),
|
||||||
|
m('button.btn.btn-error.accept-application-button', {onclick: function(){
|
||||||
|
_Admin.declineApplication(a);
|
||||||
|
}}, 'Decline')
|
||||||
|
]);
|
||||||
|
}))
|
||||||
|
]);
|
||||||
|
}}}
|
||||||
|
|
||||||
|
export default ApplicationManager;
|
@ -0,0 +1,39 @@
|
|||||||
|
import _Cart from './_Cart.js';
|
||||||
|
import BaseListItem from './BaseListItem.js';
|
||||||
|
|
||||||
|
var BaseBrowser = function(){
|
||||||
|
return {
|
||||||
|
view: function(){
|
||||||
|
var lenses = [];
|
||||||
|
return m('.base-listing', [
|
||||||
|
m('table.table.table-striped', [
|
||||||
|
m('thead', [
|
||||||
|
m('tr', [
|
||||||
|
m('th', 'Base'),
|
||||||
|
m('th', 'Add'),
|
||||||
|
m('th', 'Material'),
|
||||||
|
m('th', 'AR'),
|
||||||
|
m('th', 'Photochromatic'),
|
||||||
|
m('th', 'Price'),
|
||||||
|
m('th', 'Quantity')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('tbody', [
|
||||||
|
lenses.map(function(lens){
|
||||||
|
return m(BaseListItem, {lens: lens});
|
||||||
|
}),
|
||||||
|
m('tr', [
|
||||||
|
m('td.text-center', {colspan: 7}, [
|
||||||
|
m('button.btn.btn-primary.btn-lg.btn-block', [
|
||||||
|
m('i.icon.icon-plus')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BaseBrowser;
|
@ -0,0 +1,75 @@
|
|||||||
|
var BaseListItem = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
var lens = vnode.attrs.lens;
|
||||||
|
return m('tr', [
|
||||||
|
m('td', [ // Base
|
||||||
|
m('.form-group', [
|
||||||
|
m('select.form-select', [
|
||||||
|
m('option', {value: '2'}, 'Base 2'),
|
||||||
|
m('option', {value: '4'}, 'Base 4'),
|
||||||
|
m('option', {value: '6'}, 'Base 6'),
|
||||||
|
m('option', {value: '8'}, 'Base 8')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // Add
|
||||||
|
m('.form-group', [
|
||||||
|
m('select.form-select', [
|
||||||
|
m('option', {value: '1.00'}, '1.00'),
|
||||||
|
m('option', {value: '1.25'}, '1.25'),
|
||||||
|
m('option', {value: '1.50'}, '1.50'),
|
||||||
|
m('option', {value: '1.75'}, '1.75'),
|
||||||
|
m('option', {value: '2.00'}, '2.00'),
|
||||||
|
m('option', {value: '2.25'}, '2.25'),
|
||||||
|
m('option', {value: '2.50'}, '2.50'),
|
||||||
|
m('option', {value: '2.75'}, '2.75'),
|
||||||
|
m('option', {value: '3.00'}, '3.00')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // Material
|
||||||
|
m('.form-group', [
|
||||||
|
m('select.form-select', [
|
||||||
|
m('option', {value: 'cr39'}, 'CR39'),
|
||||||
|
m('option', {value: 'ft'}, 'F/T'),
|
||||||
|
m('option', {value: 'kriptok'}, 'Kriptok'),
|
||||||
|
m('option', {value: 'progressive'}, 'Progressive')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // AR Coating
|
||||||
|
m('.form-group', [
|
||||||
|
m('label.form-checkbox', [
|
||||||
|
m('input', {type: 'checkbox', checked: false}),
|
||||||
|
m('i.form-icon')
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // Photochromatic
|
||||||
|
m('.form-group', [
|
||||||
|
m('select.form-select', [
|
||||||
|
m('option', {value: ''}, 'None'),
|
||||||
|
m('option', {value: 'photogray'}, 'Photogray'),
|
||||||
|
m('option', {value: 'photobrown'}, 'Photobrown')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', '$3'), // Price
|
||||||
|
m('td', [ // Quantity
|
||||||
|
m('.form-group.input-group', [
|
||||||
|
m('input.form-input', {
|
||||||
|
type: 'text',
|
||||||
|
value: '0'
|
||||||
|
}),
|
||||||
|
m('button.btn.btn-primary.input-group-btn', [
|
||||||
|
m('i.icon.icon-delete')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BaseListItem;
|
@ -0,0 +1,47 @@
|
|||||||
|
var Carousel = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
var images = vnode.attrs.images;
|
||||||
|
var name = vnode.attrs.name;
|
||||||
|
|
||||||
|
return m('.carousel', [
|
||||||
|
images.map(function(image,index){
|
||||||
|
return m('input.carousel-locator', {
|
||||||
|
id: 'slide-'+index,
|
||||||
|
type: 'radio',
|
||||||
|
name: name,
|
||||||
|
hidden: true,
|
||||||
|
checked: (index===0 ? true : false)
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
m('.carousel-container', images.map(function(image, index){
|
||||||
|
var prev_index = (index === 0 ? images.length-1 : index-1);
|
||||||
|
var next_index = (index === images.length-1 ? 0 : index+1);
|
||||||
|
return m('figure.carousel-item', [
|
||||||
|
m('label.item-prev.btn.btn-action.btn-large', {
|
||||||
|
"for": 'slide-'+prev_index
|
||||||
|
}, [
|
||||||
|
m('i.icon.icon-arrow-left')
|
||||||
|
]),
|
||||||
|
m('label.item-next.btn.btn-action.btn-large', {
|
||||||
|
"for": 'slide-'+next_index
|
||||||
|
}, [
|
||||||
|
m('i.icon.icon-arrow-right')
|
||||||
|
]),
|
||||||
|
m('img.img-responsive.rounded', {
|
||||||
|
src: image.src,
|
||||||
|
alt: image.description
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
})),
|
||||||
|
m('.carousel-nav', images.map(function(image, index){
|
||||||
|
return m('label.nav-item.text-hide.c-hand',{
|
||||||
|
"for": 'slide-'+index
|
||||||
|
}, index.toString());
|
||||||
|
})),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Carousel;
|
@ -0,0 +1,77 @@
|
|||||||
|
import _Cart from './_Cart.js';
|
||||||
|
import _Item from './_Item.js';
|
||||||
|
import _User from './_User.js';
|
||||||
|
import _DB from './_DB.js';
|
||||||
|
import _Message from './_Message.js';
|
||||||
|
import toNumber from './util/toNumber.js';
|
||||||
|
import isNumber from './util/isNumber.js';
|
||||||
|
|
||||||
|
function Cart(initialVnode) {
|
||||||
|
return {
|
||||||
|
view: function(vnode) {
|
||||||
|
if(!_User.isLoggedIn()){
|
||||||
|
return m('.cart', [
|
||||||
|
m("h1.text-center", "Shopping Cart"),
|
||||||
|
m('p', 'You must be logged-in to see your cart.')
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
var grand_total = 0;
|
||||||
|
return m(".cart", [
|
||||||
|
m("h1.text-center", "Shopping Cart"),
|
||||||
|
m("table.table.table-striped.table-hover.line-item-list", [
|
||||||
|
m('thead', [
|
||||||
|
m('tr', [
|
||||||
|
m('th', 'Item'),
|
||||||
|
m('th', 'Price'),
|
||||||
|
m('th', 'Quantity'),
|
||||||
|
m('th', 'Subtotal')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('tbody',
|
||||||
|
_Cart.current.lineitem_ids.map(function(lineitem_id, lineitem_index){
|
||||||
|
var lineitem = _DB.getRecord(lineitem_id);
|
||||||
|
var item = _DB.getRecord(lineitem.item_id);
|
||||||
|
var price = lineitem.price;
|
||||||
|
var quantity = lineitem.quantity;
|
||||||
|
var sub_total = price*quantity;
|
||||||
|
grand_total += sub_total;
|
||||||
|
return m('tr.line-item', [
|
||||||
|
m('td.item-title', item.name),
|
||||||
|
m('td.price', "$"+price),
|
||||||
|
m('td', [
|
||||||
|
m('input[type=text].quantity.form-input', {
|
||||||
|
// TODO: Don't update quantity if it's not a (whole) number
|
||||||
|
onchange: function (e) {
|
||||||
|
//lineitem.quantity = toNumber(e.target.value);
|
||||||
|
var new_quantity = toNumber(e.target.value);
|
||||||
|
//if(new_quantity === 0){
|
||||||
|
// _Cart.removeLineItem(lineitem_index); // TODO: change to removeByLineitem, it's more efficient
|
||||||
|
// }
|
||||||
|
//else if(!isNumber(new_quantity)){
|
||||||
|
if(!isNumber(new_quantity)){
|
||||||
|
//console.log("Qty. is not a number.");
|
||||||
|
_Message.addError("Quantity '"+new_quantity+"' is not a number.");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
_Cart.updateQuantityOfItem(item, new_quantity);
|
||||||
|
//lineitem.quantity = new_quantity;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: lineitem.quantity
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
m('td.line-item-total', '$'+sub_total)
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
m('.total', [
|
||||||
|
m('label.grand-total-label', "Grand Total: "),
|
||||||
|
m('span.grand-total', '$'+grand_total)
|
||||||
|
]),
|
||||||
|
m("button.btn.btn-primary", {onclick: _Cart.placeOrder}, "Place Order")
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default Cart
|
@ -0,0 +1,37 @@
|
|||||||
|
import _Item from './_Item.js';
|
||||||
|
import _Navigation from './_Navigation.js';
|
||||||
|
import ItemBrowser from './ItemBrowser.js';
|
||||||
|
import _CollectionsList from './_CollectionsList.js';
|
||||||
|
import _User from './_User.js';
|
||||||
|
|
||||||
|
var CollectionsList = function(){
|
||||||
|
return {view: function(vnode){
|
||||||
|
var brands = _CollectionsList.house_brands;
|
||||||
|
return m('.container', [
|
||||||
|
m('.columns', [
|
||||||
|
m('.column.col-12', [
|
||||||
|
m('h1.text-center', 'Collections')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('.columns', brands.map(function(brand){
|
||||||
|
return m('.column.col-4.col-md-6.col-xs-12.mt-1', [
|
||||||
|
m('.card.c-hand', {onclick: function(e){
|
||||||
|
//var item_browser_attrs = {};
|
||||||
|
//item_browser_attrs.items = [];
|
||||||
|
_Item.getItems({brand:brand}).then(function(items){
|
||||||
|
//item_browser_attrs.items = items;
|
||||||
|
_Navigation.navigateTo(ItemBrowser, {items: items});
|
||||||
|
});
|
||||||
|
}},[
|
||||||
|
m('.card-header', [
|
||||||
|
m('.card-title.h3.text-center', brand)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
))
|
||||||
|
]);
|
||||||
|
}};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CollectionsList;
|
@ -0,0 +1,25 @@
|
|||||||
|
var ContactUs = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
return m('.contactus', [
|
||||||
|
m('h1.text-center', 'Contact Us'),
|
||||||
|
m('h3', ['Phone ', m('small', 'Customer Service & General Inquiries')]),
|
||||||
|
m('p', '(305)-818-6786'),
|
||||||
|
m('h3', 'Email'),
|
||||||
|
m('p', 'silvano@piazzaoptical.com'),
|
||||||
|
m('h3', 'Hours'),
|
||||||
|
m('p', 'Mon-Fri 9:00-5:30'),
|
||||||
|
m('h3', 'Address'),
|
||||||
|
m('p', [
|
||||||
|
'8200 NW 27th. Street',
|
||||||
|
m('br'),
|
||||||
|
'Suite 105',
|
||||||
|
m('br'),
|
||||||
|
'Miami, FL 33122'
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ContactUs;
|
@ -0,0 +1,38 @@
|
|||||||
|
import _Item from './_Item.js';
|
||||||
|
import _Navigation from './_Navigation.js';
|
||||||
|
import ItemBrowser from './ItemBrowser.js';
|
||||||
|
import _CollectionsList from './_CollectionsList.js';
|
||||||
|
import _User from './_User.js';
|
||||||
|
|
||||||
|
var DesignerCollectionsList = function(){
|
||||||
|
return {view: function(vnode){
|
||||||
|
var brands = _CollectionsList.designer_brands;
|
||||||
|
return m('.container', [
|
||||||
|
m('.columns', [
|
||||||
|
m('.column.col-12', [
|
||||||
|
m('h1.text-center', 'Designer Collections')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
_User.isGuest() ? m('.columns', [m('.column.col-12', 'Please Sign-In to See Designer Brands')]) :
|
||||||
|
m('.columns', brands.map(function(brand){
|
||||||
|
return m('.column.col-4.col-md-6.col-xs-12.mt-1', [
|
||||||
|
m('.card.c-hand', {onclick: function(e){
|
||||||
|
//var item_browser_attrs = {};
|
||||||
|
//item_browser_attrs.items = [];
|
||||||
|
_Item.getItems({brand:brand}).then(function(items){
|
||||||
|
//item_browser_attrs.items = items;
|
||||||
|
_Navigation.navigateTo(ItemBrowser, {items: items});
|
||||||
|
});
|
||||||
|
}},[
|
||||||
|
m('.card-header', [
|
||||||
|
m('.card-title.h3.text-center', brand)
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
))
|
||||||
|
]);
|
||||||
|
}};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DesignerCollectionsList;
|
@ -0,0 +1,15 @@
|
|||||||
|
import ItemBrowser from './ItemBrowser.js';
|
||||||
|
import _Equipment from './_Equipment.js';
|
||||||
|
|
||||||
|
var Equipment = function(){
|
||||||
|
return {
|
||||||
|
view: function(){
|
||||||
|
return m('.equipment', [
|
||||||
|
m('h1.text-center','Equipment'),
|
||||||
|
m(ItemBrowser, {items: _Equipment.items})
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Equipment;
|
@ -0,0 +1,11 @@
|
|||||||
|
var Events = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
return m('.events', [
|
||||||
|
m('h1.text-center', "Upcoming Events")
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Events;
|
@ -0,0 +1,41 @@
|
|||||||
|
var noop = function(){};
|
||||||
|
|
||||||
|
function FileUploadDropArea(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
var cb = vnode.attrs.cb;
|
||||||
|
if(typeof cb !== 'Function'){
|
||||||
|
cb = noop;
|
||||||
|
}
|
||||||
|
return m('.file-upload-drop-area',{
|
||||||
|
ondragover: function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
},
|
||||||
|
ondrop: function(e){
|
||||||
|
e.preventDefault(); // don't open the file in the browser
|
||||||
|
var files = [];
|
||||||
|
|
||||||
|
// some browsers use `.items` and some use `.files`, so check for both:
|
||||||
|
if (e.dataTransfer.items) {
|
||||||
|
for (var i = 0; i < e.dataTransfer.items.length; i++) {
|
||||||
|
if (e.dataTransfer.items[i].kind === 'file') { // If dropped items aren't files, reject them
|
||||||
|
files.push( e.dataTransfer.items[i].getAsFile() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (var i = 0; i < e.dataTransfer.files.length; i++) {
|
||||||
|
files.push( e.dataTransfer.files[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var i=0, file=null; i<files.length; i++){
|
||||||
|
file = files[i]
|
||||||
|
vnode.attrs.cb(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 'Drop files here...');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FileUploadDropArea;
|
@ -0,0 +1,65 @@
|
|||||||
|
import _FrameAdmin from './_FrameAdmin.js';
|
||||||
|
import FrameAdminListItem from './FrameAdminListItem.js';
|
||||||
|
|
||||||
|
var FrameAdmin = function(){
|
||||||
|
return {
|
||||||
|
view: function(){
|
||||||
|
var results_frames = _FrameAdmin.results_frames;
|
||||||
|
var working_frames = _FrameAdmin.working_frames;
|
||||||
|
return m('.frame-listing', [
|
||||||
|
m('h4', 'Frame Editor'),
|
||||||
|
m('.search', [
|
||||||
|
m('input[type=text][placeholder=Model]', {
|
||||||
|
onchange: _FrameAdmin.search_onchange_handler,
|
||||||
|
value: _FrameAdmin.search_term
|
||||||
|
})
|
||||||
|
]),
|
||||||
|
m('table.table.table-striped', [
|
||||||
|
m('thead', [
|
||||||
|
m('tr', [
|
||||||
|
m('th', 'Name'),
|
||||||
|
m('th', 'Brand'),
|
||||||
|
m('th', 'Model'),
|
||||||
|
m('th', 'Color Code'),
|
||||||
|
m('th', 'Color Description'),
|
||||||
|
m('th', 'Description (Short)'),
|
||||||
|
m('th', 'Size'),
|
||||||
|
m('th', 'Material'),
|
||||||
|
m('th', 'Price (Silver)'),
|
||||||
|
m('th', 'Price (Gold)'),
|
||||||
|
m('th', 'Inventory'),
|
||||||
|
m('th', 'Delete')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('tbody', [
|
||||||
|
m('tr', [
|
||||||
|
m('td.text-center', {colspan: 11}, [
|
||||||
|
m('button.btn.btn-primary.btn-lg.btn-block', {onclick: _FrameAdmin.add_button_onclick_handler}, [
|
||||||
|
m('i.icon.icon-plus'),
|
||||||
|
' Add ',
|
||||||
|
m('i.icon.icon-plus')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
working_frames.map(function(frame, i){
|
||||||
|
return m(FrameAdminListItem, {frame: frame, collection: working_frames, index_in_collection: i});
|
||||||
|
}),
|
||||||
|
m('tr', [
|
||||||
|
m('td.text-center', {colspan: 11}, [
|
||||||
|
m('button.btn.btn-primary.btn-lg.btn-block', {onclick: _FrameAdmin.clear_button_onclick_handler}, [
|
||||||
|
m('i.icon.icon-refresh'),
|
||||||
|
' Clear'
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
results_frames.map(function(frame, i){
|
||||||
|
return m(FrameAdminListItem, {frame: frame, collection: results_frames, index_in_collection: i});
|
||||||
|
})
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FrameAdmin;
|
@ -0,0 +1,94 @@
|
|||||||
|
import _FrameAdminListItem from './_FrameAdminListItem.js';
|
||||||
|
|
||||||
|
|
||||||
|
var FrameAdminListItem = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
var frame = vnode.attrs.frame;
|
||||||
|
var collection = vnode.attrs.collection;
|
||||||
|
var index_in_collection = vnode.attrs.index_in_collection;
|
||||||
|
if(frame.loading === true){
|
||||||
|
return m('tr', [
|
||||||
|
m('td', {colspan: 11}, [
|
||||||
|
m('.loading-lg')
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return m('tr', [
|
||||||
|
m('td', [
|
||||||
|
m('input', {type:'text', onchange: function(e){
|
||||||
|
_FrameAdminListItem.update(frame, 'name', e.target.value);
|
||||||
|
}, value: frame.name})
|
||||||
|
]),
|
||||||
|
m('td', [
|
||||||
|
m('input', {type:'text', onchange: function(e){
|
||||||
|
_FrameAdminListItem.update(frame, 'brand', e.target.value);
|
||||||
|
}, value: frame.brand})
|
||||||
|
]),
|
||||||
|
m('td', [
|
||||||
|
m('input', {type:'text', onchange: function(e){
|
||||||
|
_FrameAdminListItem.update(frame, 'model', e.target.value);
|
||||||
|
}, value: frame.model})
|
||||||
|
]),
|
||||||
|
m('td', [
|
||||||
|
m('input', {type:'text', onchange: function(e){
|
||||||
|
_FrameAdminListItem.update(frame, 'color', e.target.value);
|
||||||
|
}, value: frame.color})
|
||||||
|
]),
|
||||||
|
m('td', [
|
||||||
|
m('input', {type:'text', onchange: function(e){
|
||||||
|
_FrameAdminListItem.update(frame, 'color_description', e.target.value);
|
||||||
|
}, value: frame.color_description})
|
||||||
|
]),
|
||||||
|
m('td', [
|
||||||
|
m('input', {type:'text', onchange: function(e){
|
||||||
|
_FrameAdminListItem.update(frame, 'description_short', e.target.value);
|
||||||
|
}, value: frame.description_short})
|
||||||
|
]),
|
||||||
|
m('td', [
|
||||||
|
m('input', {type:'text', onchange: function(e){
|
||||||
|
_FrameAdminListItem.update(frame, 'size', e.target.value);
|
||||||
|
}, value: frame.size})
|
||||||
|
]),
|
||||||
|
m('td', [
|
||||||
|
m('input', {type:'text', onchange: function(e){
|
||||||
|
_FrameAdminListItem.update(frame, 'material', e.target.value);
|
||||||
|
}, value: frame.material})
|
||||||
|
]),
|
||||||
|
m('td', [
|
||||||
|
m('input', {type:'text', onchange: function(e){
|
||||||
|
var price = Number(e.target.value)
|
||||||
|
if(price !== NaN){
|
||||||
|
_FrameAdminListItem.update(frame, 'price_silver', price);
|
||||||
|
}
|
||||||
|
}, value: frame.price_silver})
|
||||||
|
]),
|
||||||
|
m('td', [
|
||||||
|
m('input', {type:'text', onchange: function(e){
|
||||||
|
var price = Number(e.target.value)
|
||||||
|
if(price !== NaN){
|
||||||
|
_FrameAdminListItem.update(frame, 'price_gold', price);
|
||||||
|
}
|
||||||
|
}, value: frame.price_gold})
|
||||||
|
]),
|
||||||
|
m('td', [
|
||||||
|
m('input', {type:'text', onchange: function(e){
|
||||||
|
var inventory = Number(e.target.value)
|
||||||
|
if(inventory !== NaN){
|
||||||
|
_FrameAdminListItem.update(frame, 'inventory', inventory);
|
||||||
|
}
|
||||||
|
}, value: frame.inventory})
|
||||||
|
]),
|
||||||
|
m('td', [
|
||||||
|
m('button.btn.btn-action.btn-primary.s-circle', {onclick: function(e){
|
||||||
|
_FrameAdminListItem.delete(frame, collection, index_in_collection);
|
||||||
|
}}, [m('i.icon.icon-delete')])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FrameAdminListItem;
|
@ -0,0 +1,23 @@
|
|||||||
|
import _FullscreenImage from './_FullscreenImage.js';
|
||||||
|
|
||||||
|
var FullscreenImage = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
var image = _FullscreenImage.image;
|
||||||
|
if(image === null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return m('img.img-responsive.p-fixed', {
|
||||||
|
style: 'top:0px;left:0px;',
|
||||||
|
src: (image.thumbnail_original_id ? '/thumbnailsdb/'+image.thumbnail_original_id+'.png' : image.src_base64),
|
||||||
|
onclick: function(){
|
||||||
|
_FullscreenImage.image = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FullscreenImage;
|
@ -0,0 +1,11 @@
|
|||||||
|
var Header = function(){
|
||||||
|
return m(".header", [
|
||||||
|
m("h1", "Piazza Optical"),
|
||||||
|
m(".login-box", [
|
||||||
|
m("input.username", {placeholder: "Username"}),
|
||||||
|
m("input.password", {placeholder: "Password", type:"password"})
|
||||||
|
])
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Header
|
@ -0,0 +1,15 @@
|
|||||||
|
import _Home from './_Home.js';
|
||||||
|
import Carousel from './Carousel.js';
|
||||||
|
|
||||||
|
var Home = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
return m('.home', [
|
||||||
|
//m('h1', "Piazza Optical Home Page"),
|
||||||
|
m(Carousel, {images: _Home.carousel_images, name: 'home-carousel'})
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Home;
|
@ -0,0 +1,63 @@
|
|||||||
|
import _Item from './_Item.js';
|
||||||
|
import isArray from './util/isArray.js';
|
||||||
|
|
||||||
|
var ItemChooser = function(){
|
||||||
|
var search_term = '';
|
||||||
|
var results = [];
|
||||||
|
var chosen_item = null;
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
var onchoose = vnode.attrs.onchoose;
|
||||||
|
return m('.item-search', [
|
||||||
|
m('input[type=text][placeholder=Model]', {
|
||||||
|
onchange: function(e){
|
||||||
|
search_term = e.target.value;
|
||||||
|
results = [];
|
||||||
|
if(search_term !== ''){
|
||||||
|
_Item.searchByString(search_term)
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
if(isArray(res.results)){ // empty list comes back as `{}` from server instead of `[]`
|
||||||
|
results = res.results;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
results = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: search_term
|
||||||
|
}),
|
||||||
|
m('table.table.table-striped.table-hover.results', [
|
||||||
|
m('thead', [
|
||||||
|
m('tr', [
|
||||||
|
m('th', 'Brand'),
|
||||||
|
m('th', 'Model'),
|
||||||
|
m('th', 'Color')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('tbody',
|
||||||
|
results.map(function(item){
|
||||||
|
var active_class = (chosen_item === item ? '.active' : '');
|
||||||
|
return m('tr'+active_class, {
|
||||||
|
onclick: function(e){
|
||||||
|
e.stopPropagation();
|
||||||
|
chosen_item = item;
|
||||||
|
onchoose(item);
|
||||||
|
}
|
||||||
|
},[
|
||||||
|
m('td', item.brand),
|
||||||
|
m('td', item.model),
|
||||||
|
m('td', item.color)
|
||||||
|
])
|
||||||
|
})
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ItemChooser;
|
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
function ItemFilter(initialVnode) {
|
||||||
|
return {
|
||||||
|
view: function(vnode) {
|
||||||
|
return m(".item-filter", [
|
||||||
|
m(".heading", "Brand"),
|
||||||
|
m(".heading", "Color"),
|
||||||
|
m(".heading", "Category"),
|
||||||
|
m(".heading", "Tags")
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default ItemFilter
|
@ -0,0 +1,75 @@
|
|||||||
|
import _Image from './_Image.js';
|
||||||
|
import _Item from './_Item.js';
|
||||||
|
import _DB from './_DB.js';
|
||||||
|
import _FullscreenImage from './_FullscreenImage.js';
|
||||||
|
import isObject from './util/isObject.js';
|
||||||
|
|
||||||
|
function ItemImageController(ivnode){
|
||||||
|
return { view: function(vnode){
|
||||||
|
var item = vnode.attrs.item;
|
||||||
|
if(item === null){
|
||||||
|
return m('.msg', 'No item chosen.');
|
||||||
|
}
|
||||||
|
if(typeof item.image_ids === 'undefined'){ item.image_ids=[]; }
|
||||||
|
var images = item.image_ids.map(function(image_id){
|
||||||
|
if(isObject(image_id)){
|
||||||
|
return image_id;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return _DB.getRecord(image_id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var no_images = (images.length === 0);
|
||||||
|
return m('.item-image-controller.bg-secondary.text-center', {
|
||||||
|
style: 'height: 500px;',
|
||||||
|
ondragover: function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
},
|
||||||
|
ondrop: function(e){
|
||||||
|
e.preventDefault(); // don't open the file in the browser
|
||||||
|
var files = [];
|
||||||
|
|
||||||
|
// some browsers use `.items` and some use `.files`, so check for both:
|
||||||
|
if (e.dataTransfer.items) {
|
||||||
|
for (var i = 0; i < e.dataTransfer.items.length; i++) {
|
||||||
|
if (e.dataTransfer.items[i].kind === 'file') { // If dropped items aren't files, reject them
|
||||||
|
files.push( e.dataTransfer.items[i].getAsFile() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (var i = 0; i < e.dataTransfer.files.length; i++) {
|
||||||
|
files.push( e.dataTransfer.files[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var i=0; i<files.length; i++){
|
||||||
|
_Image.newFromFile(files[i]).then(function(image){
|
||||||
|
_Item.addImage(item, image).then(m.redraw);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
m.redraw();
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
m('.container.image-list', [
|
||||||
|
m('.columns',
|
||||||
|
no_images ? [m('.column.col-12', [m('h3', 'Drop Images Here')] )] : images.map(function(image){
|
||||||
|
return m('.column.col-4', [
|
||||||
|
m('.card.c-hand', {onclick: function(){ _LargeImage.src = (image.thumbnail_original_id ? '/thumbnailsdb/'+image.thumbnail_original_id+'.png' : image.src_base64); }},[
|
||||||
|
m('figure', [
|
||||||
|
m('img.img-responsive', {src: (image.thumbnail_180_id ? _Image.thumbnailPath(image, '180') : image.src_base64) }),
|
||||||
|
m('figcaption', image.original_filename)
|
||||||
|
]),
|
||||||
|
m('button.btn.btn-clear.delete', {onclick: function(e){
|
||||||
|
e.stopPropagation();
|
||||||
|
_Item.deleteImage(item, image);
|
||||||
|
}},'Delete'),
|
||||||
|
(image.is_uploading ? m('progress.progress',{value: image.progress, max: 1.0}) : null)
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}}}
|
||||||
|
|
||||||
|
export default ItemImageController;
|
@ -0,0 +1,29 @@
|
|||||||
|
import ItemChooser from './ItemChooser.js';
|
||||||
|
import ItemImageController from './ItemImageController.js';
|
||||||
|
import _Item from './_Item.js';
|
||||||
|
|
||||||
|
function ItemImageUploader(){
|
||||||
|
var item = null;
|
||||||
|
return {
|
||||||
|
view: function(){
|
||||||
|
return m('.item-image-uploader', [
|
||||||
|
m('h2', 'Upload Images to Items'),
|
||||||
|
m('.container', [
|
||||||
|
m('.columns', [
|
||||||
|
m('.column.col-6', [
|
||||||
|
m(ItemChooser, {onchoose: function(_item){
|
||||||
|
item = _item;
|
||||||
|
_Item.loadImages(item);
|
||||||
|
}})
|
||||||
|
]),
|
||||||
|
m('.column.col-6', [
|
||||||
|
m(ItemImageController, {item: item})
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ItemImageUploader;
|
@ -0,0 +1,29 @@
|
|||||||
|
import ItemListingEntry from './ItemListingEntry.js';
|
||||||
|
import _Item from './_Item.js';
|
||||||
|
|
||||||
|
function ItemListing(initialVnode) {
|
||||||
|
var chosen_images = {
|
||||||
|
items: null,
|
||||||
|
chosen_images: []
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
view: function(vnode) {
|
||||||
|
//var items = _Item.filter(vnode.attrs.filter);
|
||||||
|
//var items = _Item.collection;
|
||||||
|
var items = vnode.attrs.items;
|
||||||
|
if(items.length === 0){
|
||||||
|
return m('h5', 'Please contact us directly to order.');
|
||||||
|
}
|
||||||
|
if(chosen_images.items !== items){
|
||||||
|
chosen_images.chosen_images = items.map(function(item){
|
||||||
|
return item.image_ids[0];
|
||||||
|
});
|
||||||
|
chosen_images.items = items;
|
||||||
|
}
|
||||||
|
return m(".columns", items.map(function(item, i){
|
||||||
|
return m(ItemListingEntry, {item:item, index: i, chosen_images: chosen_images.chosen_images})
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default ItemListing
|
@ -0,0 +1,97 @@
|
|||||||
|
//var ItemListingEntry = require('./ItemListingEntry');
|
||||||
|
import _Cart from "./_Cart.js";
|
||||||
|
import _Item from './_Item.js';
|
||||||
|
import _User from './_User.js';
|
||||||
|
import _Modal from './_Modal.js';
|
||||||
|
import _Message from './_Message.js';
|
||||||
|
import _Image from './_Image.js';
|
||||||
|
import _DB from './_DB.js';
|
||||||
|
import ItemModalView from './ItemModalView.js';
|
||||||
|
import isUndefined from './util/isUndefined.js';
|
||||||
|
import toNumber from "./util/toNumber";
|
||||||
|
import isNumber from "./util/isNumber";
|
||||||
|
|
||||||
|
function ItemListingEntry(initialVnode) {
|
||||||
|
return {
|
||||||
|
view: function(vnode) {
|
||||||
|
var item = vnode.attrs.item;
|
||||||
|
var index = vnode.attrs.index;
|
||||||
|
var chosen_images = vnode.attrs.chosen_images;
|
||||||
|
var chosen_image = chosen_images[index];
|
||||||
|
var lineitem = _Cart.lineItemOfItem(item);
|
||||||
|
var thumbnail_path = ( chosen_image ? _Image.thumbnailPath(_DB.getRecord(chosen_image), '180') : false );
|
||||||
|
return m('.column.col-3.col-md-6.col-xs-12.mt-2', [
|
||||||
|
m(".card.c-hand", {
|
||||||
|
onclick: function(e){
|
||||||
|
_Item.getFullItemInfo(item).then(function(){
|
||||||
|
_Modal.show(ItemModalView, {item: item});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},[
|
||||||
|
m('.card-image.p-centered',[
|
||||||
|
(item.image_ids.length === 0
|
||||||
|
?
|
||||||
|
m("img.img-responsive", {src: _Image.placeholder_img_180_path })
|
||||||
|
:
|
||||||
|
[
|
||||||
|
m("img.img-responsive", {src: thumbnail_path }),
|
||||||
|
m('.form-group.text-center',
|
||||||
|
item.image_ids.map(function(image_id){
|
||||||
|
return m('label.form-radio.label-sm.form-inline', [
|
||||||
|
m('input.input-sm', {
|
||||||
|
type:'radio',
|
||||||
|
name: item.id.toString(),
|
||||||
|
value: image_id, // is this converted to string?
|
||||||
|
checked: chosen_image===image_id,
|
||||||
|
onchange: function(e){
|
||||||
|
chosen_images[index] = image_id;
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
m('i.form-icon',{onclick:function(e){
|
||||||
|
chosen_images[index] = image_id;
|
||||||
|
e.stopPropagation(); // So a modal box doesn't open-up
|
||||||
|
return false; // I don't know why I need this in addition to stopPropagation().
|
||||||
|
}
|
||||||
|
},"")
|
||||||
|
])
|
||||||
|
})
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
m('.card-header', [
|
||||||
|
m(".card-title.h6.text-ellipsis", item.name),
|
||||||
|
m(".card-subtitle.text-gray", item.color),
|
||||||
|
]),
|
||||||
|
(_User.isGuest() ? null : [
|
||||||
|
m('card-body',[
|
||||||
|
m(".price", '$'+_Item.priceOf(item)),
|
||||||
|
]),
|
||||||
|
m('card-footer', [
|
||||||
|
m("input[type=text].form-input.text-center.c-auto", {
|
||||||
|
onchange: function(e){
|
||||||
|
var new_quantity = toNumber(e.target.value);
|
||||||
|
if(new_quantity === 0){
|
||||||
|
_Cart.removeByItem(item);
|
||||||
|
}
|
||||||
|
else if(!isNumber(new_quantity)){
|
||||||
|
//console.log("Qty. is not a number.");
|
||||||
|
_Message.addError("Quantity '"+new_quantity+"' is not a number.");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
_Cart.updateQuantityOfItem(item, new_quantity);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onfocus: function(e){e.target.select();},
|
||||||
|
onclick: function(e){ e.stopPropagation(); },
|
||||||
|
value: (isUndefined(lineitem) ? 0 : lineitem.quantity)
|
||||||
|
})
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default ItemListingEntry
|
@ -0,0 +1,82 @@
|
|||||||
|
import _Item from "./_Item.js";
|
||||||
|
import _Image from './_Image.js';
|
||||||
|
import _Modal from './_Modal.js';
|
||||||
|
import _User from './_User.js';
|
||||||
|
//import _LargeImage from './_LargeImage.js';
|
||||||
|
|
||||||
|
var _chosen_image = {
|
||||||
|
item: null,
|
||||||
|
chosen_image: null
|
||||||
|
};
|
||||||
|
|
||||||
|
var ItemModalView = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
var item = vnode.attrs.item;
|
||||||
|
if(_chosen_image.item !== item){
|
||||||
|
_chosen_image.item = item;
|
||||||
|
_chosen_image.chosen_image = item.image_ids[0];
|
||||||
|
}
|
||||||
|
var chosen_image = _chosen_image.chosen_image;
|
||||||
|
var thumbnail_path = ( chosen_image ? _Image.thumbnailPath(_DB.getRecord(chosen_image), '960') : false );
|
||||||
|
/*
|
||||||
|
return [
|
||||||
|
m('.modal-header', [
|
||||||
|
m('a.btn.btn-clear.float-right', {'aria-label':"Close", onclick: function(){ _Modal.close(); }}),
|
||||||
|
m('.modal-title.h4', item.name)
|
||||||
|
]),
|
||||||
|
m('.modal-body', [
|
||||||
|
m("img.img-responsive", {src: thumbnail_path || _Image.placeholder_img_960_path })
|
||||||
|
]),
|
||||||
|
m('.modal-footer', [
|
||||||
|
m('div', '$'+_Item.priceOf(item)),
|
||||||
|
m('button.btn.btn-primary', 'Add to Cart')
|
||||||
|
])
|
||||||
|
];
|
||||||
|
*/
|
||||||
|
return m('.item-modal-view', [
|
||||||
|
m('a.btn.btn-clear.float-right', {'aria-label':"Close", onclick: function(){ _Modal.close(); }}),
|
||||||
|
m('.h4.text-center', item.name),
|
||||||
|
m("img.img-responsive", {
|
||||||
|
src: thumbnail_path || _Image.placeholder_img_960_path,
|
||||||
|
onclick: function(e){
|
||||||
|
e.stopPropagation();
|
||||||
|
if(thumbnail_path !== false){
|
||||||
|
window.open(_Image.thumbnailPath(_DB.getRecord(chosen_image), 'original'), '_blank');
|
||||||
|
}
|
||||||
|
//_LargeImage.src = (thumbnail_path ? _Image.thumbnailPath(_DB.getRecord(item.image_ids[0]), 'original') : null);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
m('.form-group.text-center',
|
||||||
|
item.image_ids.map(function(image_id){
|
||||||
|
return m('label.form-radio.label-sm.form-inline', [
|
||||||
|
m('input.input-sm', {
|
||||||
|
type:'radio',
|
||||||
|
name: item.id.toString()+'modal', // to distinguish from 'ItemListingEntry' radio buttons
|
||||||
|
value: image_id, // is this converted to string?
|
||||||
|
checked: chosen_image===image_id,
|
||||||
|
onchange: function(e){
|
||||||
|
_chosen_image.chosen_image = image_id;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
m('i.form-icon',"")
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
),
|
||||||
|
m('ul', [
|
||||||
|
m('li', 'Color: '+item.color+' ('+item.color_description+')'),
|
||||||
|
m('li', 'Size: '+(item.size || 'N/A')),
|
||||||
|
m('li', 'Material: '+(item.material || 'N/A'))
|
||||||
|
]),
|
||||||
|
m('p', item.description_short),
|
||||||
|
( _User.isLoggedIn() ? [
|
||||||
|
m('div', '$'+_Item.priceOf(item) ),
|
||||||
|
m('button.btn.btn-primary', 'Add to Cart')
|
||||||
|
]
|
||||||
|
: null )
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ItemModalView;
|
@ -0,0 +1,22 @@
|
|||||||
|
import _LargeImage from './_LargeImage.js';
|
||||||
|
|
||||||
|
var LargeImage = function(){
|
||||||
|
return {
|
||||||
|
view: function(){
|
||||||
|
if(_LargeImage.src === null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return m('img.img-responsive.large-image', {
|
||||||
|
src: _LargeImage.src,
|
||||||
|
onclick: function(e){
|
||||||
|
e.stopPropagation();
|
||||||
|
_LargeImage.src = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LargeImage;
|
@ -0,0 +1,40 @@
|
|||||||
|
import _LensBrowser from './_LensBrowser.js';
|
||||||
|
import SingleVisionBrowser from './SingleVisionBrowser.js';
|
||||||
|
import MultifocalBrowser from './MultifocalBrowser.js';
|
||||||
|
import BaseBrowser from './BaseBrowser.js';
|
||||||
|
|
||||||
|
var c = function(browser){
|
||||||
|
return (_LensBrowser.browser === browser ? '.active' : '')
|
||||||
|
}
|
||||||
|
|
||||||
|
var LensBrowser = function(){
|
||||||
|
return {
|
||||||
|
view: function(){
|
||||||
|
return m('.lens-browser', [
|
||||||
|
m('h1.text-center', 'Lenses'),
|
||||||
|
m('p', '* Prices are per pair.'),
|
||||||
|
m('p', '* High strengths cost extra.'),
|
||||||
|
m('ul.tab.tab-block.c-hand', [
|
||||||
|
m('li.tab-item'+c(SingleVisionBrowser), {
|
||||||
|
onclick: function(){ _LensBrowser.browser = SingleVisionBrowser; }
|
||||||
|
}, [
|
||||||
|
m('a', 'Single-Vision')
|
||||||
|
]),
|
||||||
|
m('li.tab-item'+c(MultifocalBrowser), {
|
||||||
|
onclick: function(){ _LensBrowser.browser = MultifocalBrowser; }
|
||||||
|
}, [
|
||||||
|
m('a', 'Multifocal')
|
||||||
|
]),
|
||||||
|
m('li.tab-item'+c(BaseBrowser), {
|
||||||
|
onclick: function(){ _LensBrowser.browser = BaseBrowser; }
|
||||||
|
}, [
|
||||||
|
m('a', 'Bases')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m(_LensBrowser.browser)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LensBrowser;
|
@ -0,0 +1,50 @@
|
|||||||
|
import _Login from "./_Login.js";
|
||||||
|
import _User from "./_User.js";
|
||||||
|
import _AccountApplication from "./_AccountApplication.js";
|
||||||
|
import AccountApplicationBox from './AccountApplicationBox.js';
|
||||||
|
import _Navigation from './_Navigation.js';
|
||||||
|
|
||||||
|
var LoginBox = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
if(!_User.isLoggedIn()){
|
||||||
|
return m('.column.col-8', [
|
||||||
|
m('.form-group', [
|
||||||
|
//m('button.red',{onclick: function(){ _Login.is_hidden = true; }},'Close'),
|
||||||
|
m('.has-icon-left', [
|
||||||
|
m('input[type=text][placeholder=Username].form-input', {
|
||||||
|
onchange: function(e){ _Login.username = e.target.value; },
|
||||||
|
value: _Login.username
|
||||||
|
}),
|
||||||
|
m('i.form-icon.icon.icon-arrow-right')
|
||||||
|
]),
|
||||||
|
m('input[type=password][placeholder=Password].form-input', {
|
||||||
|
onchange: function(e){ _Login.password = e.target.value; },
|
||||||
|
value: _Login.password
|
||||||
|
}),
|
||||||
|
m('button.btn.btn-primary', {onclick: function(e){
|
||||||
|
e.preventDefault(); // this is require since the button is in a form
|
||||||
|
_User.attemptLogin(_Login.username, _Login.password);
|
||||||
|
}}, "Login"),
|
||||||
|
m('button.btn', {onclick: function(e){
|
||||||
|
e.preventDefault(); // this is require since the button is in a form
|
||||||
|
_Navigation.navigateTo(AccountApplicationBox, null);
|
||||||
|
}}, "Apply for Account")
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return m('.logout_box.column.col-11', [
|
||||||
|
m('button.btn.btn-primary', {
|
||||||
|
onclick: function(){
|
||||||
|
_User.logout();
|
||||||
|
_Login.username = "";
|
||||||
|
_Login.password = "";
|
||||||
|
}}, 'Logout')
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoginBox;
|
@ -0,0 +1,27 @@
|
|||||||
|
import _Navigation from './_Navigation.js';
|
||||||
|
import _User from './_User.js';
|
||||||
|
|
||||||
|
var MenuItem = function(){
|
||||||
|
return { view: function(vnode){
|
||||||
|
var menuitem = vnode.attrs.menuitem;
|
||||||
|
var attrs = {}
|
||||||
|
if(menuitem.component !== null || menuitem.run !== null){ // note to self for continuation: make a proper onclick handler to both navigateTo and run the 'run', or either one if only one is provided
|
||||||
|
attrs.onclick = function(){
|
||||||
|
if(menuitem.component !== null){ _Navigation.navigateTo(menuitem.component,menuitem.attrs); }
|
||||||
|
if(menuitem.run !== null){ menuitem.run(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m("a.btn.btn-link", attrs, [
|
||||||
|
menuitem.label,
|
||||||
|
m('.list',
|
||||||
|
menuitem.children.map(function(mi){
|
||||||
|
if(!menuitem.restricted || _User.isLoggedIn()){
|
||||||
|
return m(MenuItem, {menuitem: mi});
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MenuItem;
|
@ -0,0 +1,26 @@
|
|||||||
|
import _Message from "./_Message.js";
|
||||||
|
|
||||||
|
var Messages = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
return m('.messages-box.p-fixed.p-2', {style: 'left:0px;top:0px;width:100%;'},_Message.messages.map(function(msg, index){
|
||||||
|
var message_class;
|
||||||
|
if(msg.type === 'success'){
|
||||||
|
message_class = 'toast-success';
|
||||||
|
}
|
||||||
|
else if(msg.type === 'notification'){
|
||||||
|
message_class = 'toast-primary';
|
||||||
|
}
|
||||||
|
else if(msg.type === 'error'){
|
||||||
|
message_class = 'toast-error';
|
||||||
|
}
|
||||||
|
return m('.toast.'+message_class, [
|
||||||
|
m('button.btn.btn-clear.float-right', {onclick: function(){ _Message.remove(index); }}, ""),
|
||||||
|
msg.text
|
||||||
|
]);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Messages;
|
@ -0,0 +1,24 @@
|
|||||||
|
import _Modal from "./_Modal.js";
|
||||||
|
|
||||||
|
var Modal = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
var active_class = (_Modal.component === null ? '' : '.active');
|
||||||
|
return m('.modal'+active_class, [
|
||||||
|
m('a.modal-overlay', {
|
||||||
|
'aria-label':"Close",
|
||||||
|
onclick: function(){ _Modal.close(); }
|
||||||
|
}),
|
||||||
|
m('.modal-container', [
|
||||||
|
(_Modal.component === null ?
|
||||||
|
''
|
||||||
|
:
|
||||||
|
m(_Modal.component, _Modal.attrs)
|
||||||
|
)
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Modal;
|
@ -0,0 +1,40 @@
|
|||||||
|
import _Cart from './_Cart.js';
|
||||||
|
import MultifocalListItem from './MultifocalListItem.js';
|
||||||
|
|
||||||
|
var MultifocalBrowser = function(){
|
||||||
|
return {
|
||||||
|
view: function(){
|
||||||
|
var lenses = [];
|
||||||
|
return m('.multifocal-listing', [
|
||||||
|
m('table.table.table-striped', [
|
||||||
|
m('thead', [
|
||||||
|
m('tr', [
|
||||||
|
m('th', '#1'),
|
||||||
|
m('th', '#2'), // TODO: what's this called again?
|
||||||
|
m('th', 'Material'),
|
||||||
|
m('th', 'Type'),
|
||||||
|
m('th', 'AR'),
|
||||||
|
m('th', 'Photochromatic'),
|
||||||
|
m('th', 'Price'),
|
||||||
|
m('th', 'Quantity')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('tbody', [
|
||||||
|
lenses.map(function(lens){
|
||||||
|
return m(MultifocalListItem, {lens: lens});
|
||||||
|
}),
|
||||||
|
m('tr', [
|
||||||
|
m('td.text-center', {colspan: 8}, [
|
||||||
|
m('button.btn.btn-primary.btn-lg.btn-block', [
|
||||||
|
m('i.icon.icon-plus')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MultifocalBrowser;
|
@ -0,0 +1,93 @@
|
|||||||
|
var MultifocalListItem = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
var lens = vnode.attrs.lens;
|
||||||
|
return m('tr', [
|
||||||
|
m('td', [ // Strength #1
|
||||||
|
m('.form-group', [
|
||||||
|
m('select.form-select', [
|
||||||
|
m('option', {value: '0.00'}, '0.00'),
|
||||||
|
m('option', {value: '0.25'}, '0.25'),
|
||||||
|
m('option', {value: '0.50'}, '0.50'),
|
||||||
|
m('option', {value: '0.75'}, '0.75'),
|
||||||
|
m('option', {value: '1.00'}, '1.00'),
|
||||||
|
m('option', {value: '1.25'}, '1.25'),
|
||||||
|
m('option', {value: '1.50'}, '1.50'),
|
||||||
|
m('option', {value: '1.75'}, '1.75'),
|
||||||
|
m('option', {value: '2.00'}, '2.00'),
|
||||||
|
m('option', {value: '2.25'}, '2.25'),
|
||||||
|
m('option', {value: '2.50'}, '2.50'),
|
||||||
|
m('option', {value: '2.75'}, '2.75'),
|
||||||
|
m('option', {value: '3.00'}, '3.00')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // Strength #2
|
||||||
|
m('.form-group', [
|
||||||
|
m('select.form-select', [
|
||||||
|
m('option', {value: '1.00'}, '1.00'),
|
||||||
|
m('option', {value: '1.25'}, '1.25'),
|
||||||
|
m('option', {value: '1.50'}, '1.50'),
|
||||||
|
m('option', {value: '1.75'}, '1.75'),
|
||||||
|
m('option', {value: '2.00'}, '2.00'),
|
||||||
|
m('option', {value: '2.25'}, '2.25'),
|
||||||
|
m('option', {value: '2.50'}, '2.50'),
|
||||||
|
m('option', {value: '2.75'}, '2.75'),
|
||||||
|
m('option', {value: '3.00'}, '3.00')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // Material
|
||||||
|
m('.form-group', [
|
||||||
|
m('select.form-select', [
|
||||||
|
m('option', {value: 'cr39'}, 'CR39'),
|
||||||
|
m('option', {value: 'polycarbonate'}, 'Polycarbonate'),
|
||||||
|
m('option', {value: 'blue-bocker'}, 'Blue Bocker'),
|
||||||
|
m('option', {value: 'glass'}, 'Glass')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // Multifocal Type
|
||||||
|
m('.form-group', [
|
||||||
|
m('select.form-select', [
|
||||||
|
m('option', {value: 'progressive'}, 'Progressive'),
|
||||||
|
m('option', {value: 'ft28'}, 'FT28'),
|
||||||
|
m('option', {value: 'blended'}, 'Blended')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // AR Coating
|
||||||
|
m('.form-group', [
|
||||||
|
m('label.form-checkbox', [
|
||||||
|
m('input', {type: 'checkbox', checked: false}),
|
||||||
|
m('i.form-icon')
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // Photochromatic
|
||||||
|
m('.form-group', [
|
||||||
|
m('select.form-select', [
|
||||||
|
m('option', {value: ''}, 'None'),
|
||||||
|
m('option', {value: 'photogray'}, 'Photogray'),
|
||||||
|
m('option', {value: 'photobrown'}, 'Photobrown')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', '$3'), // Price
|
||||||
|
m('td', [ // Quantity
|
||||||
|
m('.form-group.input-group', [
|
||||||
|
m('input.form-input', {
|
||||||
|
type: 'text',
|
||||||
|
value: '0'
|
||||||
|
}),
|
||||||
|
m('button.btn.btn-primary.input-group-btn', [
|
||||||
|
m('i.icon.icon-delete')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MultifocalListItem;
|
@ -0,0 +1,121 @@
|
|||||||
|
import _Navigation from './_Navigation.js';
|
||||||
|
import _User from './_User.js';
|
||||||
|
import MenuItem from './MenuItem.js';
|
||||||
|
|
||||||
|
var Navigation = function(){
|
||||||
|
return {view: function(){
|
||||||
|
var hidden_class = _Navigation.is_hidden ?'.hidden':'';
|
||||||
|
var v = m("section.navbar-section", _Navigation.menu.map(function(menuitem){
|
||||||
|
if(!menuitem.restricted){
|
||||||
|
return m(MenuItem, {menuitem: menuitem})
|
||||||
|
}
|
||||||
|
else if(menuitem.restricted === 'admin' && _User.isAdmin()){
|
||||||
|
return m(MenuItem, {menuitem: menuitem})
|
||||||
|
}
|
||||||
|
else if(menuitem.restricted === true && _User.isLoggedIn()){
|
||||||
|
return m(MenuItem, {menuitem: menuitem})
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
return m('header.navbar'+hidden_class, [
|
||||||
|
//m('button',{onclick: function(){ _Navigation.is_hidden = true; }},'Close'),
|
||||||
|
v
|
||||||
|
]);
|
||||||
|
/*
|
||||||
|
return m("ul.flex.items-center.justify-center.bg-gray-900.text-white.cursor-default", [
|
||||||
|
m("li", [
|
||||||
|
m(".hover:bg-gray-700.rounded.px-2.py-1.text-center", {onclick: navigateTo(Home,null)}, "Home")
|
||||||
|
]),
|
||||||
|
m("li", [
|
||||||
|
m(".hover:bg-gray-700.rounded.px-2.py-1.text-center", {onclick: navigateTo(AboutUs,null)}, "About Us")
|
||||||
|
]),
|
||||||
|
m("li", [
|
||||||
|
m(".hover:bg-gray-700.rounded.px-2.py-1.text-center", {onclick: navigateTo(Events,null)}, "Events"),
|
||||||
|
m(".menu.hidden", [
|
||||||
|
m(".item", "Upcoming Trade Shows")
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m("li", [
|
||||||
|
m(".hover:bg-gray-700.rounded.px-2.py-1.text-center", "Collections Catalog"),
|
||||||
|
m(".menu.hidden", [
|
||||||
|
m(".section-heading", "Optical Frames"),
|
||||||
|
m(".heading", "Style"),
|
||||||
|
m(".subheading", "Adults"),
|
||||||
|
m(".item", {onclick: navigateTo(ItemBrowser, {filter:{type: "frame", gender: "mens"}})}, "Mens"),
|
||||||
|
m(".item", "Womens"),
|
||||||
|
m(".item", "Unisex"),
|
||||||
|
m(".subheading.item", "Teens"),
|
||||||
|
m(".subheading.item", "Kids"),
|
||||||
|
m(".heading", "Material"),
|
||||||
|
m(".subheading", "Plastic"),
|
||||||
|
m(".item", "Acetate"),
|
||||||
|
m(".item", "TR90 & Silicone"),
|
||||||
|
m(".item", "Injection"),
|
||||||
|
m(".subheading", "Metal"),
|
||||||
|
m(".item", "Aluminum"),
|
||||||
|
m(".item", "Monel"),
|
||||||
|
m(".item", "Stainless Steel"),
|
||||||
|
m(".item", "Titanium"),
|
||||||
|
m(".section-heading", "Sunglasses"),
|
||||||
|
m(".heading", "Brand"),
|
||||||
|
m(".subheading.item", "Designer Brands"),
|
||||||
|
m(".subheading", "Exclusive Labels"),
|
||||||
|
m(".item", "Kadima"),
|
||||||
|
m(".item", "Kapricci"),
|
||||||
|
m(".item", "Bubble Gum"),
|
||||||
|
m(".item", "Primmera"),
|
||||||
|
m(".heading", "Gender"),
|
||||||
|
m(".item", "Mens"),
|
||||||
|
m(".item", "Womens"),
|
||||||
|
m(".item", "Unisex"),
|
||||||
|
m(".heading.item", "Clearance Items")
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m("li", [
|
||||||
|
m(".hover:bg-gray-700.rounded.px-2.py-1.text-center", "Lenses"),
|
||||||
|
m(".menu.hidden", [
|
||||||
|
m(".section-heading", "Finished"),
|
||||||
|
m(".heading", "Blue Bocker"),
|
||||||
|
m(".heading", "Single Vision"),
|
||||||
|
m(".heading", "Multifocals"),
|
||||||
|
m(".section-heading", "Semi-Finished"),
|
||||||
|
m(".heading", "Blue Bocker"),
|
||||||
|
m(".heading", "Single Vision"),
|
||||||
|
m(".heading", "Multifocals")
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m("li", [
|
||||||
|
m(".hover:bg-gray-700.rounded.px-2.py-1.text-center", "Equipment"),
|
||||||
|
m(".menu.hidden", [
|
||||||
|
m(".heading", "Autorefractometer"),
|
||||||
|
m(".heading", "Chart Projector"),
|
||||||
|
m(".heading", "Lensometer"),
|
||||||
|
m(".heading", "Ophthalmoscope"),
|
||||||
|
m(".heading", "Pachimeter"),
|
||||||
|
m(".heading", "Phoropter"),
|
||||||
|
m(".heading", "Prism bar"),
|
||||||
|
m(".heading", "Pupilometer"),
|
||||||
|
m(".heading", "Retinoscope"),
|
||||||
|
m(".heading", "Slit Lamp"),
|
||||||
|
m(".heading", "Trial Lens Set"),
|
||||||
|
m(".item", "*104 pcs"),
|
||||||
|
m(".item", "*158 pcs"),
|
||||||
|
m(".item", "*232 pcs"),
|
||||||
|
m(".item", "*266 pcs")
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m("li", [
|
||||||
|
m(".hover:bg-gray-700.rounded.px-2.py-1.text-center", "Accessories"),
|
||||||
|
m(".menu.hidden", [
|
||||||
|
m(".heading", "Cases"),
|
||||||
|
m(".heading", "Cords"),
|
||||||
|
m(".heading", "Microfiber Cloth Lens Cleaner"),
|
||||||
|
m(".heading", "Lens Cleaner Bottles"),
|
||||||
|
m(".heading", "Nosepads"),
|
||||||
|
m(".heading", "Screws")
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
*/
|
||||||
|
}}}
|
||||||
|
|
||||||
|
export default Navigation;
|
@ -0,0 +1,48 @@
|
|||||||
|
import _OpenOrders from './_OpenOrders.js';
|
||||||
|
import _Navigation from './_Navigation.js';
|
||||||
|
import OrderView from './OrderView.js';
|
||||||
|
import _DB from './_DB.js';
|
||||||
|
|
||||||
|
var OpenOrders = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
return m('.open-orders', [
|
||||||
|
m('h2', 'Open Orders'),
|
||||||
|
m('button.btn.refresh-application-button',{onclick: function(){
|
||||||
|
_OpenOrders.getOpenOrders();
|
||||||
|
}},[m('i.icon.icon-refresh'), 'Refresh']),
|
||||||
|
m('.order-list',
|
||||||
|
m('table.table.table-striped.table-hover', [
|
||||||
|
m('thead', [
|
||||||
|
m('tr', [
|
||||||
|
m('th', 'Customer'),
|
||||||
|
m('th', 'Date Ordered'),
|
||||||
|
m('th', 'Order Number')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('tbody',
|
||||||
|
_OpenOrders.orders.map(function(order){
|
||||||
|
var user = _DB.getRecord(order.user_id);
|
||||||
|
var company_name = user.store || 'No Company: User#'+user.id;
|
||||||
|
var date_ordered = order.date_ordered;
|
||||||
|
var order_number = order.id;
|
||||||
|
return m('tr', {onclick: function(e){
|
||||||
|
e.stopPropagation();
|
||||||
|
_OpenOrders.loadOrder(order).then(function(order){
|
||||||
|
_Navigation.navigateTo(OrderView, {order: order});
|
||||||
|
});
|
||||||
|
}},[
|
||||||
|
m('td', company_name),
|
||||||
|
m('td', date_ordered),
|
||||||
|
m('td', order_number)
|
||||||
|
])
|
||||||
|
})
|
||||||
|
)
|
||||||
|
])
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OpenOrders;
|
@ -0,0 +1,103 @@
|
|||||||
|
import _DB from './_DB.js';
|
||||||
|
|
||||||
|
var OrderView = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
var order = vnode.attrs.order;
|
||||||
|
var user = _DB.getRecord(order.user_id);
|
||||||
|
var cart = _DB.getRecord(order.cart_id)
|
||||||
|
var lineitems = cart.lineitem_ids.map(_DB.getRecord);
|
||||||
|
var cart_total = 0;
|
||||||
|
return m('.order-view', [
|
||||||
|
m('h1', [
|
||||||
|
'Order #'+order.id,
|
||||||
|
m('small', 'Ordered On: '+order.date_ordered)
|
||||||
|
]),
|
||||||
|
m('p', user.store+' ('+user.firstname+' '+user.lastname+')'),
|
||||||
|
( order.status === 'open'
|
||||||
|
?
|
||||||
|
m('button.btn.btn-primary',{onclick: function(e){
|
||||||
|
_DB.setProperty(order, 'status', 'closed');
|
||||||
|
}},'Close Order')
|
||||||
|
:
|
||||||
|
m('button.btn.btn-primary',{onclick: function(e){
|
||||||
|
_DB.setProperty(order, 'status', 'open');
|
||||||
|
}},'Re-open Order')
|
||||||
|
),
|
||||||
|
m('.steps', [
|
||||||
|
m('ul.step', [
|
||||||
|
m('li.step-item'+(order.progress==='ordered'?'.active':''), [
|
||||||
|
m('a.tooltip', {
|
||||||
|
href:'#',
|
||||||
|
'data-tooltip':'Customer Placed Order on '+order.date_ordered,
|
||||||
|
onclick: function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
_DB.setProperty(order, 'progress', 'ordered');
|
||||||
|
}
|
||||||
|
}, 'Ordered')
|
||||||
|
]),
|
||||||
|
m('li.step-item'+(order.progress==='picked'?'.active':''), [
|
||||||
|
m('a.tooltip', {
|
||||||
|
href:'#',
|
||||||
|
'data-tooltip':'Piazza Picked the Order',
|
||||||
|
onclick: function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
_DB.setProperty(order, 'progress', 'picked');
|
||||||
|
}
|
||||||
|
}, 'Picked')
|
||||||
|
]),
|
||||||
|
m('li.step-item'+(order.progress==='shipped'?'.active':''), [
|
||||||
|
m('a.tooltip', {
|
||||||
|
href:'#',
|
||||||
|
'data-tooltip':'Piazza Shipped the Order',
|
||||||
|
onclick: function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
_DB.setProperty(order, 'progress', 'shipped');
|
||||||
|
}
|
||||||
|
}, 'Shipped')
|
||||||
|
]),
|
||||||
|
m('li.step-item'+(order.progress==='paid'?'.active':''), [
|
||||||
|
m('a.tooltip', {
|
||||||
|
href:'#',
|
||||||
|
'data-tooltip':'Customer Paid for the Order in Full',
|
||||||
|
onclick: function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
_DB.setProperty(order, 'progress', 'paid');
|
||||||
|
}
|
||||||
|
}, 'Paid')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('.items', [
|
||||||
|
m('table.table.table-striped.table-hover', [
|
||||||
|
m('thead', [
|
||||||
|
m('tr', [
|
||||||
|
m('th', 'Item'),
|
||||||
|
m('th', 'Quantity'),
|
||||||
|
m('th', 'Price'),
|
||||||
|
m('th', 'Subtotal')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('tbody', lineitems.map(function(lineitem){
|
||||||
|
var subtotal = lineitem.quantity*lineitem.price;
|
||||||
|
cart_total += subtotal;
|
||||||
|
return m('tr', [
|
||||||
|
m('td', _DB.getRecord(lineitem.item_id).name),
|
||||||
|
m('td', lineitem.quantity),
|
||||||
|
m('td', '$'+lineitem.price),
|
||||||
|
m('td', '$'+subtotal)
|
||||||
|
]);
|
||||||
|
}))
|
||||||
|
]),
|
||||||
|
m('h6', "Grand Total: $"+cart_total)
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OrderView;
|
@ -0,0 +1,39 @@
|
|||||||
|
import _Cart from './_Cart.js';
|
||||||
|
import SingleVisionListItem from './SingleVisionListItem.js';
|
||||||
|
|
||||||
|
var SingleVisionBrowser = function(){
|
||||||
|
return {
|
||||||
|
view: function(){
|
||||||
|
var lenses = [];
|
||||||
|
return m('.single-vision-listing', [
|
||||||
|
m('table.table.table-striped', [
|
||||||
|
m('thead', [
|
||||||
|
m('tr', [
|
||||||
|
m('th', 'SPH'),
|
||||||
|
m('th', 'CYL'),
|
||||||
|
m('th', 'Material'),
|
||||||
|
m('th', 'AR'),
|
||||||
|
m('th', 'Photochromatic'),
|
||||||
|
m('th', 'Price'),
|
||||||
|
m('th', 'Quantity')
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('tbody', [
|
||||||
|
lenses.map(function(lens){
|
||||||
|
return m(SingleVisionListItem, {lens: lens});
|
||||||
|
}),
|
||||||
|
m('tr', [
|
||||||
|
m('td.text-center', {colspan: 7}, [
|
||||||
|
m('button.btn.btn-primary.btn-lg.btn-block', [
|
||||||
|
m('i.icon.icon-plus')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SingleVisionBrowser;
|
@ -0,0 +1,108 @@
|
|||||||
|
var SingleVisionListItem = function(){
|
||||||
|
return {
|
||||||
|
view: function(vnode){
|
||||||
|
var lens = vnode.attrs.lens;
|
||||||
|
return m('tr', [
|
||||||
|
m('td', [ // SPH
|
||||||
|
m('.form-group.sph', [
|
||||||
|
m('select.form-select.form-inline', [
|
||||||
|
m('option', {value: '-'}, '-'),
|
||||||
|
m('option', {value: '+'}, '+')
|
||||||
|
]),
|
||||||
|
m('select.form-select.form-inline', [
|
||||||
|
m('option', {value: '0.00'}, '0.00'),
|
||||||
|
m('option', {value: '0.25'}, '0.25'),
|
||||||
|
m('option', {value: '0.50'}, '0.50'),
|
||||||
|
m('option', {value: '0.75'}, '0.75'),
|
||||||
|
m('option', {value: '1.00'}, '1.00'),
|
||||||
|
m('option', {value: '1.25'}, '1.25'),
|
||||||
|
m('option', {value: '1.50'}, '1.50'),
|
||||||
|
m('option', {value: '1.75'}, '1.75'),
|
||||||
|
m('option', {value: '2.00'}, '2.00'),
|
||||||
|
m('option', {value: '2.25'}, '2.25'),
|
||||||
|
m('option', {value: '2.50'}, '2.50'),
|
||||||
|
m('option', {value: '2.75'}, '2.75'),
|
||||||
|
m('option', {value: '3.00'}, '3.00'),
|
||||||
|
m('option', {value: '3.25'}, '3.25'),
|
||||||
|
m('option', {value: '3.50'}, '3.50'),
|
||||||
|
m('option', {value: '3.75'}, '3.75'),
|
||||||
|
m('option', {value: '4.00'}, '4.00'),
|
||||||
|
m('option', {value: '4.25'}, '4.25'),
|
||||||
|
m('option', {value: '4.50'}, '4.50'),
|
||||||
|
m('option', {value: '4.75'}, '4.75'),
|
||||||
|
m('option', {value: '5.00'}, '5.00'),
|
||||||
|
m('option', {value: '5.25'}, '5.25'),
|
||||||
|
m('option', {value: '5.50'}, '5.50'),
|
||||||
|
m('option', {value: '5.75'}, '5.75'),
|
||||||
|
m('option', {value: '6.00'}, '6.00'),
|
||||||
|
m('option', {value: '6.25'}, '6.25'),
|
||||||
|
m('option', {value: '6.50'}, '6.50'),
|
||||||
|
m('option', {value: '6.75'}, '6.75'),
|
||||||
|
m('option', {value: '7.00'}, '7.00')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // CYL
|
||||||
|
m('.form-group', [
|
||||||
|
m('select.form-select', [
|
||||||
|
m('option', {value: '0.00'}, '0.00'),
|
||||||
|
m('option', {value: '0.25'}, '0.25'),
|
||||||
|
m('option', {value: '0.50'}, '0.50'),
|
||||||
|
m('option', {value: '0.75'}, '0.75'),
|
||||||
|
m('option', {value: '1.00'}, '1.00'),
|
||||||
|
m('option', {value: '1.25'}, '1.25'),
|
||||||
|
m('option', {value: '1.50'}, '1.50'),
|
||||||
|
m('option', {value: '1.75'}, '1.75'),
|
||||||
|
m('option', {value: '2.00'}, '2.00'),
|
||||||
|
m('option', {value: '2.25'}, '2.25'),
|
||||||
|
m('option', {value: '2.50'}, '2.50'),
|
||||||
|
m('option', {value: '2.75'}, '2.75'),
|
||||||
|
m('option', {value: '3.00'}, '3.00')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // Material
|
||||||
|
m('.form-group', [
|
||||||
|
m('select.form-select', [
|
||||||
|
m('option', {value: 'cr39'}, 'CR39'),
|
||||||
|
m('option', {value: 'polycarbonate'}, 'Polycarbonate'),
|
||||||
|
m('option', {value: 'blue-bocker'}, 'Blue Bocker'),
|
||||||
|
m('option', {value: 'glass'}, 'Glass')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // AR Coating
|
||||||
|
m('.form-group', [
|
||||||
|
m('label.form-checkbox', [
|
||||||
|
m('input', {type: 'checkbox', checked: false}),
|
||||||
|
m('i.form-icon')
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', [ // Transition/Photochromatic
|
||||||
|
m('.form-group', [
|
||||||
|
m('select.form-select', [
|
||||||
|
m('option', {value: ''}, 'None'),
|
||||||
|
m('option', {value: 'photogray'}, 'Photogray'),
|
||||||
|
m('option', {value: 'photobrown'}, 'Photobrown')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m('td', '$3'), // Price
|
||||||
|
m('td', [ // Quantity
|
||||||
|
m('.form-group.input-group', [
|
||||||
|
m('input.form-input', {
|
||||||
|
type: 'text',
|
||||||
|
value: '0'
|
||||||
|
}),
|
||||||
|
m('button.btn.btn-primary.input-group-btn', [
|
||||||
|
m('i.icon.icon-delete')
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SingleVisionListItem;
|
@ -0,0 +1,9 @@
|
|||||||
|
function UnderConstruction(initialVnode) {
|
||||||
|
return {
|
||||||
|
view: function(vnode) {
|
||||||
|
return m('h1.text-center.under-construction', 'Under Construction!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UnderConstruction;
|
@ -0,0 +1,5 @@
|
|||||||
|
var _Accessories = {};
|
||||||
|
|
||||||
|
_Accessories.items = [];
|
||||||
|
|
||||||
|
export default _Accessories;
|
@ -0,0 +1,82 @@
|
|||||||
|
import _Message from './_Message.js';
|
||||||
|
|
||||||
|
var _AccountApplication = {}
|
||||||
|
|
||||||
|
//_AccountApplication._show = false;
|
||||||
|
_AccountApplication.username = '';
|
||||||
|
_AccountApplication.salutation = '';
|
||||||
|
_AccountApplication.firstname = '';
|
||||||
|
_AccountApplication.lastname = '';
|
||||||
|
_AccountApplication.position = '';
|
||||||
|
_AccountApplication.store = '';
|
||||||
|
_AccountApplication.address = '';
|
||||||
|
_AccountApplication.practice_type = '';
|
||||||
|
_AccountApplication.phone_office = '';
|
||||||
|
_AccountApplication.phone_cell = '';
|
||||||
|
_AccountApplication.email = '';
|
||||||
|
|
||||||
|
_AccountApplication.salutations = [
|
||||||
|
{value: 'mr', text: 'Mr.'},
|
||||||
|
{value: 'ms', text: 'Ms.'},
|
||||||
|
{value: 'mrs', text: 'Mrs.'},
|
||||||
|
{value: 'dr', text: 'Dr.'}
|
||||||
|
];
|
||||||
|
_AccountApplication.positions = [
|
||||||
|
{value: 'owner', text: 'Owner'},
|
||||||
|
{value: 'manager', text: 'Manager'},
|
||||||
|
{value: 'buyer', text: 'Buyer'},
|
||||||
|
{value: 'other', text: 'Other'}
|
||||||
|
];
|
||||||
|
_AccountApplication.practice_types = [
|
||||||
|
{value: 'optometrist', text: 'Optometrist'},
|
||||||
|
{value: 'ophthalmologist', text: 'Ophthalmologist'},
|
||||||
|
{value: 'optician', text: 'Optician'},
|
||||||
|
{value: 'optical_retail_store', text: 'Optical Retail Store'},
|
||||||
|
{value: 'optical_lab', text: 'Optical Lab'},
|
||||||
|
{value: 'importer_distributor', text: 'Importer/Distributor'}
|
||||||
|
];
|
||||||
|
|
||||||
|
//_AccountApplication.show = function(){
|
||||||
|
// _AccountApplication._show = true;
|
||||||
|
// };
|
||||||
|
//_AccountApplication.hide = function(){
|
||||||
|
// _AccountApplication._show = false;
|
||||||
|
// };
|
||||||
|
//_AccountApplication.isShowing = function(){
|
||||||
|
// return _AccountApplication._show === true;
|
||||||
|
// };
|
||||||
|
_AccountApplication.submit = function(){
|
||||||
|
m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/submitnewuserapplication',
|
||||||
|
body: {
|
||||||
|
username: _AccountApplication.username,
|
||||||
|
salutation: _AccountApplication.salutation,
|
||||||
|
firstname: _AccountApplication.firstname,
|
||||||
|
lastname: _AccountApplication.lastname,
|
||||||
|
position: _AccountApplication.position,
|
||||||
|
store: _AccountApplication.store,
|
||||||
|
address: _AccountApplication.address,
|
||||||
|
practice_type: _AccountApplication.practice_type,
|
||||||
|
phone_office: _AccountApplication.phone_office,
|
||||||
|
phone_cell: _AccountApplication.phone_cell,
|
||||||
|
email: _AccountApplication.email
|
||||||
|
}
|
||||||
|
}).then(function(){
|
||||||
|
_Message.addNotification('Application Submitted!');
|
||||||
|
_AccountApplication._show = false;
|
||||||
|
_AccountApplication.username = '';
|
||||||
|
_AccountApplication.salutation = '';
|
||||||
|
_AccountApplication.firstname = '';
|
||||||
|
_AccountApplication.lastname = '';
|
||||||
|
_AccountApplication.position = '';
|
||||||
|
_AccountApplication.store = '';
|
||||||
|
_AccountApplication.address = '';
|
||||||
|
_AccountApplication.practice_type = '';
|
||||||
|
_AccountApplication.phone_office = '';
|
||||||
|
_AccountApplication.phone_cell = '';
|
||||||
|
_AccountApplication.email = '';
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _AccountApplication;
|
@ -0,0 +1,47 @@
|
|||||||
|
import _User from './_User.js';
|
||||||
|
import OpenOrders from './OpenOrders.js';
|
||||||
|
import util from './util.js';
|
||||||
|
|
||||||
|
var _Admin = {}
|
||||||
|
|
||||||
|
_Admin.page = OpenOrders;
|
||||||
|
|
||||||
|
_Admin.open_applications = [];
|
||||||
|
|
||||||
|
_Admin.getOpenApplications = function(){
|
||||||
|
return m.request({
|
||||||
|
method:'POST',
|
||||||
|
url: '/cgi/listnewuserapplications',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
_Admin.open_applications = res.open_applications;
|
||||||
|
// the server encodes an empty set as an Object instead of Array, so we have to detect it:
|
||||||
|
if(typeof _Admin.open_applications.length === 'undefined'){
|
||||||
|
_Admin.open_applications = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_Admin.acceptApplication = function(a){
|
||||||
|
return m.request({
|
||||||
|
method:'POST',
|
||||||
|
url: '/cgi/acceptnewuserapplication',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
application_id: a.id,
|
||||||
|
password: a.password
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
util.remove(_Admin.open_applications, a); // TODO: maybe get whole new list of open application IDs, instead of assuming the only change was this one. What if two admins are signed-on to two computers, each knocking-off open applications?
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _Admin;
|
@ -0,0 +1,74 @@
|
|||||||
|
import isUndefined from './util/isUndefined.js';
|
||||||
|
import _LineItem from './_LineItem.js';
|
||||||
|
import _Message from './_Message.js';
|
||||||
|
import _User from './_User.js';
|
||||||
|
import remove from './util/remove.js';
|
||||||
|
import removeByIndex from './util/removeByIndex.js';
|
||||||
|
|
||||||
|
var _Cart = {};
|
||||||
|
|
||||||
|
_Cart.updateQuantityOfItem = function(item, quantity){
|
||||||
|
/*
|
||||||
|
var possible_lineitem = _Cart.lineItemOfItem(item); // _Cart.current.lineitems.find(function(lineitem){ return lineitem.item.id === item.id; });
|
||||||
|
if(isUndefined(possible_lineitem)){
|
||||||
|
possible_lineitem = _LineItem.createFromItem(item);
|
||||||
|
// possible_lineitem = _Cart.add(item);
|
||||||
|
}
|
||||||
|
possible_lineitem.quantity = quantity;
|
||||||
|
*/
|
||||||
|
return m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/updateitemquantityincart',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
item_id: item.id,
|
||||||
|
quantity: quantity
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
res.lineitems.forEach(function(lineitem, index){
|
||||||
|
lineitem.item_id = _DB.integrate(lineitem.item_id).id // at first item_id has the actual object, which we integrate into _DB, but then we set it to the ID as is expected
|
||||||
|
res.lineitems[index] = _DB.integrate(lineitem).id;
|
||||||
|
});
|
||||||
|
_Cart.current.lineitem_ids = res.lineitems; // at this point, res.lineitems contains only IDs
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
_Message.addError("There was an error adding to cart.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
_Cart.removeLineItemOfItem = function(item){
|
||||||
|
// TODO: do this on server-side, and return updated cart record with updated lineitem_ids
|
||||||
|
remove(_Cart.current.lineitem_ids, function(lineitem_id){ return lineitem_id === item.id; });
|
||||||
|
};
|
||||||
|
_Cart.removeLineItem = function(index){
|
||||||
|
// TODO: do this on server-side, and return updated cart record with updated lineitem_ids
|
||||||
|
removeByIndex(_Cart.current.lineitem_ids, index);
|
||||||
|
};
|
||||||
|
_Cart.lineItemOfItem = function(item){
|
||||||
|
if(_Cart.current !== null){
|
||||||
|
return _DB.getRecord( _Cart.current.lineitem_ids.find(function(lineitem_id){ return _DB.getRecord(lineitem_id).item_id === item.id; }) );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_Cart.placeOrder = function(){
|
||||||
|
m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/placeorder',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash
|
||||||
|
}})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success){
|
||||||
|
_Message.addNotification("Order #"+ res.order_id +" Received!");
|
||||||
|
_Cart.current = res.new_cart_record;
|
||||||
|
_Cart.current.lineitem_ids = [];
|
||||||
|
_DB.integrate(_Cart.current)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_Cart.current = null; //_Cart.new();
|
||||||
|
|
||||||
|
export default _Cart;
|
@ -0,0 +1,66 @@
|
|||||||
|
var _CollectionsList = {};
|
||||||
|
|
||||||
|
_CollectionsList.house_brands = [
|
||||||
|
'Kadima',
|
||||||
|
'Kapricci',
|
||||||
|
'BubbleGum',
|
||||||
|
'Primmera'
|
||||||
|
];
|
||||||
|
_CollectionsList.designer_brands = [
|
||||||
|
//'Kadima',
|
||||||
|
//'Kapricci',
|
||||||
|
//'BubbleGum',
|
||||||
|
//'Primmera',
|
||||||
|
'Adidas',
|
||||||
|
'Armani Exchange',
|
||||||
|
'Bvlgari',
|
||||||
|
'Burberry',
|
||||||
|
'Calvin Klein',
|
||||||
|
'Carolina Herrera',
|
||||||
|
'Carrera',
|
||||||
|
'Christian Dior',
|
||||||
|
'Coach',
|
||||||
|
'Converse',
|
||||||
|
'Diesel',
|
||||||
|
'Dolce Gabbana',
|
||||||
|
'Emporio Armani',
|
||||||
|
'Ermenegildo Zegna',
|
||||||
|
'Escada',
|
||||||
|
'Fendi',
|
||||||
|
'Fila',
|
||||||
|
'Furla',
|
||||||
|
'Gant',
|
||||||
|
'Giorgio Armani',
|
||||||
|
'Gucci',
|
||||||
|
'Guess',
|
||||||
|
'Harley Davidson',
|
||||||
|
'Hugo Boss',
|
||||||
|
'Just Cavalli',
|
||||||
|
'Kenneth Cole Reaction',
|
||||||
|
'Kenneth Cole New York',
|
||||||
|
'Lacoste',
|
||||||
|
'Michael Kors',
|
||||||
|
'Mont Blanc',
|
||||||
|
'Nike',
|
||||||
|
'Nina Ricci',
|
||||||
|
'Oakley',
|
||||||
|
'Persol',
|
||||||
|
'Prada',
|
||||||
|
'Prada Sport',
|
||||||
|
'Puma',
|
||||||
|
'Ray Ban',
|
||||||
|
'Roberto Cavalli',
|
||||||
|
'Salvatore Ferragamo',
|
||||||
|
'Silhouette',
|
||||||
|
'Skechers',
|
||||||
|
'Timberland',
|
||||||
|
'Tom Ford',
|
||||||
|
'Tommy Hilfiger',
|
||||||
|
'Tory Burch',
|
||||||
|
'Tous',
|
||||||
|
'Valentino',
|
||||||
|
'Versace',
|
||||||
|
'Vogue'
|
||||||
|
];
|
||||||
|
|
||||||
|
export default _CollectionsList;
|
@ -0,0 +1,169 @@
|
|||||||
|
import _User from './_User.js';
|
||||||
|
import isArray from './util/isArray.js';
|
||||||
|
import isUndefined from './util/isUndefined.js';
|
||||||
|
|
||||||
|
var _DB = {};
|
||||||
|
|
||||||
|
_DB.records = {};
|
||||||
|
|
||||||
|
_DB.insertRecord = function(record, type, structure){
|
||||||
|
if(!isUndefined(type)){ record.type = type; }
|
||||||
|
var record_copy = _DB.copyAndTransform(record, structure); // make a copy in case the record has references to other objects, possibly circular
|
||||||
|
// TODO: Figure-out what to do for image, which has long `src_base64` property, so it must be stored in a file, with a mere reference in the DB. Also, upon creation the automatically makes thumbnails and updates the record accordingly, which is not possible to trigger.
|
||||||
|
return m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/insertrecord',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
record: record_copy
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
record.id = res.id;
|
||||||
|
_DB.integrate(record);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_DB.getRecord = function(id){
|
||||||
|
return _DB.records[id];
|
||||||
|
};
|
||||||
|
|
||||||
|
_DB.removeRecord = function(record){
|
||||||
|
delete _DB.records[record.id];
|
||||||
|
// TODO: make a call to server too? This is called by _Item.deleteImage, which itself calls the server anyway because deleting an image has special logic
|
||||||
|
}
|
||||||
|
|
||||||
|
_DB.integrate = function(new_record){
|
||||||
|
// check if record "exists" by id:
|
||||||
|
if(_DB.records.hasOwnProperty(new_record.id)){
|
||||||
|
// if it does exist, update its properties
|
||||||
|
var old_record = _DB.records[new_record.id];
|
||||||
|
Object.keys(new_record).forEach(function(key){
|
||||||
|
old_record[key] = new_record[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
// if it doesn't exist, make it
|
||||||
|
_DB.records[new_record.id] = new_record;
|
||||||
|
}
|
||||||
|
return _DB.records[new_record.id]; // in case we want the latest version of the record; see _OpenOrders for an example
|
||||||
|
};
|
||||||
|
|
||||||
|
_DB.integrateAll = function(new_records){
|
||||||
|
new_records.forEach(function(new_record, i){ // TODO: ensure this is best behavior e.g. cart.lineitems; we want the latest lineitem list, with the proper things removed and added, not only added and none removed
|
||||||
|
new_records[i] = _DB.integrate(new_record);
|
||||||
|
});
|
||||||
|
return new_records;
|
||||||
|
};
|
||||||
|
_DB.integrateAllReturnIds = function(new_records){
|
||||||
|
new_records.forEach(function(new_record, i){ // TODO: ensure this is best behavior e.g. cart.lineitems; we want the latest lineitem list, with the proper things removed and added, not only added and none removed
|
||||||
|
new_records[i] = _DB.integrate(new_record).id;
|
||||||
|
});
|
||||||
|
return new_records;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// determines whether to replace the whole array, or append to the existsing array, etc.
|
||||||
|
_DB.integrateArray = function(record_id, property, new_array){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
schema = {
|
||||||
|
id: 'copy',
|
||||||
|
brand: 'copy',
|
||||||
|
item: 'replace-with-id', // only get the id of the record, don't copy it
|
||||||
|
item2: {
|
||||||
|
id: 'copy', // automatically makes separate top-level record for item2, and sets `record.item2 = item2`
|
||||||
|
brand: 'copy'
|
||||||
|
},
|
||||||
|
lineitems: [
|
||||||
|
'list', // shows that this is a list
|
||||||
|
{ // this is the substructure of each element in the list
|
||||||
|
id: 'copy', // if substructure is left-out, then it's a list of scalars
|
||||||
|
quantity: 'copy' // if substructure == 'replace-with-id', it's a list of records, but only ids are transferred
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
_DB.getOne = function(id, type, structure){
|
||||||
|
return m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/getone',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
id: id,
|
||||||
|
type: type,
|
||||||
|
structure: structure
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
_DB.integrate(res.record);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* // exclude: big security problem, since record permissions aren't individualized; an attacker could just send an empty `structure` and get the whole DB
|
||||||
|
_DB.getAll = function(filter, structure){
|
||||||
|
return m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/getall',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
filter: filter,
|
||||||
|
structure: structure
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
if(!isArray(res.records)){ res.records = []; } // the JSON encoder sends an empty array as an object instead of array
|
||||||
|
res.records.forEach(_DB.integrate);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
_DB.setProperty = function(record, key, value){
|
||||||
|
var old_value = record[key];
|
||||||
|
record[key] = value;
|
||||||
|
return m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/setproperty',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
record_id: record.id,
|
||||||
|
record_type: record.type,
|
||||||
|
key: key,
|
||||||
|
value: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
record[key] = old_value;
|
||||||
|
_Message.addError('There was an error updating '+record.type+' #'+record.id+'.');
|
||||||
|
return old_value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_DB.copyAndTransform = function(record, structure){
|
||||||
|
var record_copy = {};
|
||||||
|
Object.keys(structure).forEach(function(key){
|
||||||
|
var operation = structure[key];
|
||||||
|
if(operation === 'copy'){
|
||||||
|
record_copy[key] = record[key];
|
||||||
|
}
|
||||||
|
else if(operation === 'replace-with-id'){
|
||||||
|
record_copy[key] = record[key].id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return record_copy;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _DB;
|
@ -0,0 +1,5 @@
|
|||||||
|
var _Equipment = {};
|
||||||
|
|
||||||
|
_Equipment.items = [];
|
||||||
|
|
||||||
|
export default _Equipment;
|
@ -0,0 +1,18 @@
|
|||||||
|
var _File = {};
|
||||||
|
|
||||||
|
_File.readAsBase64 = function(file){
|
||||||
|
var reader = new FileReader();
|
||||||
|
|
||||||
|
return new Promise(function(resolve, reject){
|
||||||
|
reader.onerror = function(){
|
||||||
|
reader.abort();
|
||||||
|
reject('Problem reading file.');
|
||||||
|
};
|
||||||
|
reader.onload = function(){
|
||||||
|
resolve(reader.result);
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _File;
|
@ -0,0 +1,60 @@
|
|||||||
|
import _Item from './_Item.js';
|
||||||
|
import _User from './_User.js';
|
||||||
|
import isArray from './util/isArray.js';
|
||||||
|
|
||||||
|
var _FrameAdmin = {};
|
||||||
|
|
||||||
|
_FrameAdmin.search_term = '';
|
||||||
|
_FrameAdmin.working_frames = [];
|
||||||
|
_FrameAdmin.results_frames = [];
|
||||||
|
|
||||||
|
_FrameAdmin.search_onchange_handler = function(e){
|
||||||
|
_FrameAdmin.search_term = e.target.value;
|
||||||
|
_FrameAdmin.results_frames = [];
|
||||||
|
if(_FrameAdmin.search_term !== ''){
|
||||||
|
//return _Item.searchByString(_FrameAdmin.search_term)
|
||||||
|
return m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/framesbystring',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
search_string: _FrameAdmin.search_term
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
if(isArray(res.results)){ // empty list comes back as `{}` from server instead of `[]`
|
||||||
|
_FrameAdmin.results_frames = res.results;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
_FrameAdmin.results_frames = [];
|
||||||
|
}
|
||||||
|
return _FrameAdmin.results_frames;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_FrameAdmin.add_button_onclick_handler = function(e){
|
||||||
|
var loading_placeholder = {loading: true};
|
||||||
|
loading_placeholder.index = _FrameAdmin.working_frames.push(loading_placeholder);
|
||||||
|
return m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/createnewframe',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash
|
||||||
|
}
|
||||||
|
}).then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
_DB.integrate(res.new_frame);
|
||||||
|
_FrameAdmin.working_frames[loading_placeholder.index] = res.new_frame;
|
||||||
|
//_FrameAdmin.working_frames.push({idname: '', brand: '', model: '', color: '', color_description: '', description_short: '', size: '', material: '', price_silver: 0.00, price_gold: 0.00});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_FrameAdmin.clear_button_onclick_handler = function(e){
|
||||||
|
_FrameAdmin.working_frames = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _FrameAdmin;
|
@ -0,0 +1,41 @@
|
|||||||
|
import _User from './_User.js';
|
||||||
|
|
||||||
|
var _FrameAdminListItem = {};
|
||||||
|
|
||||||
|
_FrameAdminListItem.update = function(frame, property, value){
|
||||||
|
var properties_to_update = {};
|
||||||
|
properties_to_update[property] = value;
|
||||||
|
return m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/updateitem',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
item_id: frame.id,
|
||||||
|
properties_to_update: properties_to_update
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
frame[property] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_FrameAdminListItem.delete = function(frame, collection, index_in_collection){
|
||||||
|
return m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/deleteitem',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
item_id: frame.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
_DB.removeRecord(frame);
|
||||||
|
collection.splice(index_in_collection, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _FrameAdminListItem;
|
@ -0,0 +1,5 @@
|
|||||||
|
var _FullscreenImage = {};
|
||||||
|
|
||||||
|
_FullscreenImage.image = null;
|
||||||
|
|
||||||
|
export default _FullscreenImage;
|
@ -0,0 +1,9 @@
|
|||||||
|
var _Home = {};
|
||||||
|
|
||||||
|
_Home.carousel_images = [
|
||||||
|
{src: 'images/carousel1-960.jpg', description: 'Stylish Frames'},
|
||||||
|
{src: 'images/carousel2-960.jpg', description: 'Piazza Optical'},
|
||||||
|
{src: 'images/carousel3-960.jpg', description: 'Professional Optical Equipment'}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default _Home;
|
@ -0,0 +1,49 @@
|
|||||||
|
import _User from './_User.js';
|
||||||
|
import _File from './_File.js';
|
||||||
|
import isUndefined from './util/isUndefined.js';
|
||||||
|
|
||||||
|
var _Image = {};
|
||||||
|
|
||||||
|
_Image.placeholder_img_180_path = './images/placeholder-180x180.png';
|
||||||
|
_Image.placeholder_img_960_path = './images/placeholder-960x720.png';
|
||||||
|
|
||||||
|
// Make a temporary Image instance (for use before it's uploaded); it cannot and should not be attached to item.image_ids. Once it's uploaded, the server returns a proper Image record, which can be attached to item.image_ids.
|
||||||
|
_Image.newFromFile = function(file){
|
||||||
|
var image = {};
|
||||||
|
image.original_filename = file.name; // TODO: extract only filename without the path
|
||||||
|
return _File.readAsBase64(file)
|
||||||
|
.then(function(src_base64){
|
||||||
|
image.src_base64 = src_base64;
|
||||||
|
return image;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
_Image.upload = function(image){
|
||||||
|
return m.request({
|
||||||
|
method: "POST",
|
||||||
|
url: "/cgi/newimage",
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
image_base64: image.src_base64,
|
||||||
|
original_filename: image.original_filename
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
_Image.addToItem = function(image, item){
|
||||||
|
return _Item.addImage(item, image);
|
||||||
|
};
|
||||||
|
|
||||||
|
_Image.thumbnailPath = function(image, size){
|
||||||
|
var thumbnail_id = image['thumbnail_'+size+'_id'];
|
||||||
|
if(isUndefined(thumbnail_id)){
|
||||||
|
return _Image['placeholder_img_'+size+'_path']
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return '/thumbnailsdb/'+thumbnail_id+'.png';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _Image;
|
@ -0,0 +1,169 @@
|
|||||||
|
import _User from "./_User.js";
|
||||||
|
import _Message from "./_Message.js";
|
||||||
|
import isUndefined from "./util/isUndefined.js";
|
||||||
|
import isArray from "./util/isArray.js";
|
||||||
|
import remove from "./util/removeElement.js";
|
||||||
|
//import filterCollection from "./lodash-es/filter.js";
|
||||||
|
|
||||||
|
var _Item = {};
|
||||||
|
|
||||||
|
_Item.collection = [];
|
||||||
|
|
||||||
|
_Item.priceOf = function(item){
|
||||||
|
if(isUndefined(item.price_user)){
|
||||||
|
if(_User.isGold()){
|
||||||
|
return item.price_gold;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return item.price_silver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return item.price_user;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Rationale for model-specific accessors like this, instead of directly using the general `_DB` module:
|
||||||
|
Each model, whether for reads or writes on the server, may have special logic.
|
||||||
|
For example, items. If a user isn't logged-in, only certain brands may be returned by the server.
|
||||||
|
Another example, images. When a new image record is inserted into the DB, it saves the binary image data to a file, makes thumbnails, and saves the files' paths in the record, and returns the entire record to the client to update the path info.
|
||||||
|
These can be accomplished by having a very smart client `_DB` module, which can direct each individual step on the server (e.g. make thumbnail, save to file, etc.).
|
||||||
|
However, it's dangerous for a client to have the ability to "send code" to the server. The logic should reside on the server, only invoked by the client.
|
||||||
|
Another problem with this is that it would require a lot of round-trips -- one for each step.
|
||||||
|
Another problem is that it's harder to implement atomic modifications. For example, if making a thumbnail fails, the entire image record is discarded from the DB. (This isn't actually the desired behavior, this is just for illustration.)
|
||||||
|
In conclusion, we've opted for model-specific getters/setters, both on client and on server.
|
||||||
|
|
||||||
|
However, the model-specific logic on both ends should still make sure to integrate data they receive into the DB, to keep all data in one place, and not have a bunch of copies of data with the same 'id' but different properties.
|
||||||
|
*/
|
||||||
|
_Item.getItems = function(filter){
|
||||||
|
return m.request({
|
||||||
|
method:"POST",
|
||||||
|
url:"/cgi/itemsbyfilter",
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
filter:filter
|
||||||
|
}})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
// the server encodes an empty set as an Object instead of Array, so we have to detect it:
|
||||||
|
if(!isArray(res.items)){
|
||||||
|
res.items = [];
|
||||||
|
}
|
||||||
|
res.items.forEach(function(item, index){
|
||||||
|
if(!isArray(item.image_ids)){
|
||||||
|
item.image_ids = [];
|
||||||
|
}
|
||||||
|
_DB.integrateAllReturnIds(item.image_ids); // converts objects to ids in-place
|
||||||
|
res.items[index] = _DB.integrate(item); // TODO: ensure all integrations are captured and return, as this is, so everything refers to the same record in the DB
|
||||||
|
});
|
||||||
|
return res.items;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_Item.getFullItemInfo = function(item){
|
||||||
|
return m.request({
|
||||||
|
method:"POST",
|
||||||
|
url:"/cgi/fulliteminfo",
|
||||||
|
body: {
|
||||||
|
item_id: item.id
|
||||||
|
}})
|
||||||
|
.then(function(res){
|
||||||
|
var item = _DB.integrate(res.item);
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_Item.searchByString = function(search_string){
|
||||||
|
return m.request({
|
||||||
|
method:"POST",
|
||||||
|
url:"/cgi/itemsbystring",
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
search_string: search_string
|
||||||
|
}});
|
||||||
|
};
|
||||||
|
|
||||||
|
_Item.addImage = function(item, image){
|
||||||
|
var image_index = item.image_ids.push(image) - 1;
|
||||||
|
return m.request({
|
||||||
|
method:"POST",
|
||||||
|
url:"/cgi/addimagetoitem",
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
item_id: item.id,
|
||||||
|
image_base64: image.src_base64,
|
||||||
|
original_filename: image.original_filename
|
||||||
|
},
|
||||||
|
config: function(xhr){
|
||||||
|
image.is_uploading = true;
|
||||||
|
image.progress = 0;
|
||||||
|
xhr.addEventListener('progress', function(e){
|
||||||
|
image.progress = e.loaded / e.total;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
delete image.is_uploading;
|
||||||
|
delete image.progress;
|
||||||
|
if(res.success === true){
|
||||||
|
_Message.addSuccess("Uploaded "+image.original_filename);
|
||||||
|
// At this point, `image` is still not its own record in `_DB`
|
||||||
|
// `image` has a large `src_base64` property, whereas `res.image` has a bunch of properties which were set by the server, namely the paths to the different thumbnails of the image, and the original
|
||||||
|
// Therefore, we choose to integrate `res.image` into `_DB`, and simply attach
|
||||||
|
item.image_ids[image_index] = res.image.id;
|
||||||
|
res.image = _DB.integrate(res.image);
|
||||||
|
return res.image;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
res.errors.forEach(function(err){
|
||||||
|
_Message.addError("Error uploading "+image.original_filename+": "+err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_Item.loadImages = function(item){
|
||||||
|
return m.request({
|
||||||
|
method:"POST",
|
||||||
|
url:"/cgi/itemimages",
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
item_id: item.id
|
||||||
|
}})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
var images;
|
||||||
|
if(isArray(res.images)){
|
||||||
|
images = _DB.integrateAll(res.images);
|
||||||
|
item.image_ids = res.images.map(function(i){ return i.id; });
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
item.image_ids = [];
|
||||||
|
images = [];
|
||||||
|
}
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
res.errors.forEach(function(err){
|
||||||
|
_Message.addError("Error uploading "+image.original_filename+": "+err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_Item.deleteImage = function(item, image){
|
||||||
|
remove(item.image_ids, image.id);
|
||||||
|
_DB.removeRecord(image);
|
||||||
|
return m.request({
|
||||||
|
method:"POST",
|
||||||
|
url:"/cgi/deleteitemimage",
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
item_id: item.id,
|
||||||
|
image_id: image.id
|
||||||
|
}});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _Item;
|
@ -0,0 +1,5 @@
|
|||||||
|
var _LargeImage = {};
|
||||||
|
|
||||||
|
_LargeImage.src = null;
|
||||||
|
|
||||||
|
export default _LargeImage;
|
@ -0,0 +1,7 @@
|
|||||||
|
import SingleVisionBrowser from './SingleVisionBrowser.js';
|
||||||
|
|
||||||
|
var _LensBrowser = {}
|
||||||
|
|
||||||
|
_LensBrowser.browser = SingleVisionBrowser;
|
||||||
|
|
||||||
|
export default _LensBrowser;
|
@ -0,0 +1,13 @@
|
|||||||
|
import _Item from './_Item.js';
|
||||||
|
|
||||||
|
var _LineItem = {
|
||||||
|
createFromItem: function(item){
|
||||||
|
var lineitem = {};
|
||||||
|
lineitem.item = item;
|
||||||
|
lineitem.quantity = 1;
|
||||||
|
lineitem.price = _Item.priceOf(item); // store price, because if a customer changes pricing tiers, and then looks back at his purchase history, it should show the price he paid at the time, not what he would pay if he would make that same order now.
|
||||||
|
return lineitem;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _LineItem;
|
@ -0,0 +1,8 @@
|
|||||||
|
var _Login = {};
|
||||||
|
|
||||||
|
_Login.username = "";
|
||||||
|
_Login.password = "";
|
||||||
|
|
||||||
|
_Login.is_hidden = true;
|
||||||
|
|
||||||
|
export default _Login;
|
@ -0,0 +1,26 @@
|
|||||||
|
var _Message = {}
|
||||||
|
|
||||||
|
_Message.messages = [];
|
||||||
|
|
||||||
|
_Message.add = function(type, msg_text){
|
||||||
|
var msg = {type: type, text: msg_text};
|
||||||
|
_Message.messages.push(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
_Message.addSuccess = function(msg_text){
|
||||||
|
_Message.add('success', msg_text);
|
||||||
|
};
|
||||||
|
|
||||||
|
_Message.addNotification = function(msg_text){
|
||||||
|
_Message.add('notification', msg_text);
|
||||||
|
};
|
||||||
|
|
||||||
|
_Message.addError = function(msg_text){
|
||||||
|
_Message.add('error', msg_text);
|
||||||
|
};
|
||||||
|
|
||||||
|
_Message.remove = function(index){
|
||||||
|
_Message.messages.splice(index,1);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _Message;
|
@ -0,0 +1,14 @@
|
|||||||
|
var _Modal = {};
|
||||||
|
|
||||||
|
_Modal.component = null;
|
||||||
|
_Modal.attrs = null;
|
||||||
|
_Modal.show = function(component, attrs){
|
||||||
|
_Modal.component = component;
|
||||||
|
_Modal.attrs = attrs;
|
||||||
|
};
|
||||||
|
_Modal.close = function(){
|
||||||
|
_Modal.component = null;
|
||||||
|
_Modal.attrs = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _Modal;
|
@ -0,0 +1,61 @@
|
|||||||
|
import Home from './Home.js';
|
||||||
|
import AboutUs from './AboutUs.js';
|
||||||
|
import Events from './Events.js';
|
||||||
|
import Policies from './Policies.js';
|
||||||
|
import ContactUs from './ContactUs.js';
|
||||||
|
import CollectionsList from './CollectionsList.js';
|
||||||
|
import DesignerCollectionsList from './DesignerCollectionsList.js';
|
||||||
|
import LensBrowser from './LensBrowser.js';
|
||||||
|
import Equipment from './Equipment.js';
|
||||||
|
import _Equipment from './_Equipment.js';
|
||||||
|
import Accessories from './Accessories.js';
|
||||||
|
import _Accessories from './_Accessories.js';
|
||||||
|
import _Item from './_Item.js';
|
||||||
|
import Admin from './Admin.js';
|
||||||
|
import UnderConstruction from './UnderConstruction.js';
|
||||||
|
|
||||||
|
var _Navigation = {};
|
||||||
|
|
||||||
|
_Navigation.is_hidden = true;
|
||||||
|
|
||||||
|
_Navigation.component = Home;
|
||||||
|
_Navigation.attrs = null;
|
||||||
|
|
||||||
|
_Navigation.navigateTo = function(component, attrs){
|
||||||
|
_Navigation.component = component;
|
||||||
|
_Navigation.attrs = attrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
_Navigation.navigateToFunction = function(component, attrs){
|
||||||
|
return function(e){
|
||||||
|
_Navigation.component = component;
|
||||||
|
_Navigation.attrs = attrs;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
_Navigation.menu = [
|
||||||
|
{label: "Home", component: Home, attrs: null, children: [], run: null, restricted: false},
|
||||||
|
{label: "About Us", component: AboutUs, attrs: null, children: [], run: null, restricted: false},
|
||||||
|
{label: "Events", component: Events, attrs: null, children: [
|
||||||
|
//{label: "Upcoming Trade Shows", component: Events, attrs: null, children: [], run: null, restricted: false}
|
||||||
|
], run: null, restricted: false},
|
||||||
|
{label: "Collections", component: CollectionsList, attrs: null, children: [], run: null},
|
||||||
|
{label: "Designer Collections", component: DesignerCollectionsList, attrs: null, children: [], run: null},
|
||||||
|
//{label: "Lenses", component: LensBrowser, attrs: null, children: [], run: null, restricted: false},
|
||||||
|
{label: "Lenses", component: UnderConstruction, attrs: null, children: [], run: null, restricted: false},
|
||||||
|
{label: "Equipment", component: Equipment, attrs: null, children: [], run: function(){
|
||||||
|
_Equipment.items=[];
|
||||||
|
_Item.getItems({subtype:'equipment'})
|
||||||
|
.then(function(items){ _Equipment.items=items; });
|
||||||
|
}, restricted: false},
|
||||||
|
{label: "Accessories", component: Accessories, attrs: null, children: [], run: function(){
|
||||||
|
_Accessories.items=[];
|
||||||
|
_Item.getItems({subtype:'accessory'})
|
||||||
|
.then(function(items){ _Accessories.items=items; });
|
||||||
|
}, restricted: false},
|
||||||
|
{label: "Contact Us", component: ContactUs, attrs: null, children: [], run: null, restricted: false},
|
||||||
|
{label: "Policies", component: Policies, attrs: null, children: [], run: null, restricted: false},
|
||||||
|
{label: "Admin", component: Admin, attrs: null, children: [], run: null, restricted: 'admin'}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default _Navigation;
|
@ -0,0 +1,67 @@
|
|||||||
|
import _DB from './_DB.js';
|
||||||
|
import _Message from './_Message.js';
|
||||||
|
import _User from './_User.js';
|
||||||
|
import isArray from './util/isArray.js';
|
||||||
|
|
||||||
|
var _OpenOrders = {};
|
||||||
|
|
||||||
|
_OpenOrders.orders = [];
|
||||||
|
|
||||||
|
_OpenOrders.getOpenOrders = function(){
|
||||||
|
return m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/listopenorders',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
if(!isArray(res.orders)){
|
||||||
|
res.orders = [];
|
||||||
|
}
|
||||||
|
_OpenOrders.orders = res.orders;
|
||||||
|
_OpenOrders.orders.forEach(function(order){
|
||||||
|
order.user_id = _DB.integrate(order.user_id).id;
|
||||||
|
_DB.integrate(order);
|
||||||
|
});
|
||||||
|
return _OpenOrders.orders;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
res.errors.forEach(function(err){
|
||||||
|
_Message.addError("Error getting open Orders: "+err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_OpenOrders.loadOrder = function(order){
|
||||||
|
return m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/loadorder',
|
||||||
|
body: {
|
||||||
|
session_hash: _User.session_hash,
|
||||||
|
order_id: order.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
order = res.order;
|
||||||
|
order.cart_id.lineitem_ids.forEach(function(lineitem){
|
||||||
|
lineitem.item_id = _DB.integrate(lineitem.item_id).id;
|
||||||
|
});
|
||||||
|
_DB.integrateAllReturnIds(order.cart_id.lineitem_ids); // integrateAll modifies the Array in-place, so no need for '='
|
||||||
|
order.cart_id = _DB.integrate(order.cart_id).id;
|
||||||
|
order = _DB.integrate(res.order);
|
||||||
|
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
res.errors.forEach(function(err){
|
||||||
|
_Message.addError("Error loading Order #"+order.id+": "+err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _OpenOrders;
|
@ -0,0 +1,39 @@
|
|||||||
|
var _Root = {};
|
||||||
|
|
||||||
|
_Root.attrs = {};
|
||||||
|
|
||||||
|
_Root.allowFileDrop = function(cb){
|
||||||
|
_Root.attrs.ondragover = function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
_Root.attrs.ondrop = function(e){
|
||||||
|
e.preventDefault(); // don't open the file in the browser
|
||||||
|
var files = [];
|
||||||
|
|
||||||
|
// some browsers use `.items` and some use `.files`, so check for both:
|
||||||
|
if (e.dataTransfer.items) {
|
||||||
|
for (var i = 0; i < e.dataTransfer.items.length; i++) {
|
||||||
|
if (e.dataTransfer.items[i].kind === 'file') { // If dropped items aren't files, reject them
|
||||||
|
files.push( e.dataTransfer.items[i].getAsFile() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (var i = 0; i < e.dataTransfer.files.length; i++) {
|
||||||
|
files.push( e.dataTransfer.files[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var i=0, file=null; i<files.length; i++){
|
||||||
|
file = files[i]
|
||||||
|
cb(file)
|
||||||
|
//console.log(file.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_Root.unallowFileDrop = function(){
|
||||||
|
_Root.attrs.ondragover = null;
|
||||||
|
_Root.attrs.ondrop = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _Root;
|
@ -0,0 +1,85 @@
|
|||||||
|
import _Message from "./_Message.js";
|
||||||
|
import isUndefined from './util/isUndefined.js';
|
||||||
|
import isArray from './util/isArray.js';
|
||||||
|
import Home from './Home.js';
|
||||||
|
import _Cart from './_Cart.js';
|
||||||
|
import _DB from './_DB.js';
|
||||||
|
import _Navigation from './_Navigation.js';
|
||||||
|
|
||||||
|
|
||||||
|
var _User = {};
|
||||||
|
|
||||||
|
_User.guest = {tier: 'silver'};
|
||||||
|
_User.current = _User.guest;
|
||||||
|
|
||||||
|
_User.session_hash = null;
|
||||||
|
|
||||||
|
_User.isGold = function(){
|
||||||
|
return _User.current.tier === 'gold';
|
||||||
|
}
|
||||||
|
|
||||||
|
_User.isLoggedIn = function(){
|
||||||
|
return !(_User.current === _User.guest);
|
||||||
|
};
|
||||||
|
|
||||||
|
_User.isGuest = function(){
|
||||||
|
return (_User.current === _User.guest);
|
||||||
|
};
|
||||||
|
|
||||||
|
_User.isAdmin = function(){
|
||||||
|
return (_User.current.is_admin);
|
||||||
|
};
|
||||||
|
|
||||||
|
_User.attemptLogin = function(username, password){
|
||||||
|
m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/attemptlogin',
|
||||||
|
body: { username: username, password: password }
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
var user = res.user;
|
||||||
|
_User.current = user;
|
||||||
|
_User.session_hash = res.session_hash;
|
||||||
|
_Message.addNotification("Welcome, "+user.firstname+"!");
|
||||||
|
|
||||||
|
if(!isArray(res.cart.lineitem_ids)){
|
||||||
|
res.cart.lineitem_ids = [];
|
||||||
|
}
|
||||||
|
res.cart.lineitem_ids.forEach(function(lineitem, index){
|
||||||
|
lineitem.item_id = _DB.integrate(lineitem.item_id).id;
|
||||||
|
res.cart.lineitem_ids[index] = _DB.integrate(lineitem).id;
|
||||||
|
});
|
||||||
|
_Cart.current = _DB.integrate(res.cart);
|
||||||
|
|
||||||
|
return _Cart.current;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
_Message.addError("Wrong Username/Password!");
|
||||||
|
//return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_User.logout = function(){
|
||||||
|
m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/logout',
|
||||||
|
body: { session_hash: _User.session_hash }
|
||||||
|
})
|
||||||
|
.then(function(res){
|
||||||
|
if(res.success === true){
|
||||||
|
_User.current = _User.guest;
|
||||||
|
_User.session_hash = null;
|
||||||
|
_Cart.current = null;
|
||||||
|
_Message.addNotification("Logged out!");
|
||||||
|
_Navigation.component = Home;
|
||||||
|
_Navigation.attrs = null;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
_Message.addError("Couldn't log out for some reason...");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default _User;
|
@ -0,0 +1,60 @@
|
|||||||
|
var root = document.body
|
||||||
|
|
||||||
|
//import Header from'./Header.js';
|
||||||
|
import _Root from './_Root.js';
|
||||||
|
import Navigation from './Navigation.js';
|
||||||
|
import _Navigation from './_Navigation.js';
|
||||||
|
import Cart from './Cart.js';
|
||||||
|
//import _Cart from './_Cart.js';
|
||||||
|
//import ItemBrowser from './ItemBrowser.js';
|
||||||
|
import Messages from './Messages.js';
|
||||||
|
import LoginBox from './LoginBox.js';
|
||||||
|
import _Login from './_Login.js';
|
||||||
|
import Modal from './Modal.js';
|
||||||
|
//import LargeImage from './LargeImage.js';
|
||||||
|
|
||||||
|
import _DB from './_DB.js';
|
||||||
|
window._DB = _DB;
|
||||||
|
|
||||||
|
var Page = {
|
||||||
|
view: function(){
|
||||||
|
return [
|
||||||
|
m('#root.container.grid-lg', _Root.attrs, [
|
||||||
|
m('#head.columns', [
|
||||||
|
m('img.img-responsive.column.col-3', {src: 'images/piazza-optical-logo.jpg'}),
|
||||||
|
m(LoginBox),
|
||||||
|
m('.column.col-1', [
|
||||||
|
m('button.btn.btn-primary', {onclick: _Navigation.navigateToFunction(Cart,null)}, [
|
||||||
|
m('i.icon-basket'),
|
||||||
|
'Cart'
|
||||||
|
])
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
m(Navigation),
|
||||||
|
m('#main', [
|
||||||
|
m(_Navigation.component, _Navigation.attrs)
|
||||||
|
//m(ItemBrowser)
|
||||||
|
]),
|
||||||
|
m(Modal),
|
||||||
|
//m(LargeImage),
|
||||||
|
m(Messages) // last so it's always on top
|
||||||
|
]),
|
||||||
|
m("#footer.bg-dark", [
|
||||||
|
m("h6#copyright.text-center", "Copyright ©2019 Piazza Optical")
|
||||||
|
])
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
m.mount(root, Page);
|
||||||
|
|
||||||
|
// TODO: get rid of this function in production
|
||||||
|
function api(endpoint, payload){
|
||||||
|
return m.request({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/cgi/'+endpoint,
|
||||||
|
body: payload
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.api = api;
|
||||||
|
|
||||||
|
//module.exports = {};
|
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#rollup app_mithril.js --file bundle.js --format iife
|
||||||
|
rollup --config
|
||||||
|
#postcss css/tailwind.css -o css/tailwind.compiled.css
|
||||||
|
#./serve.sh
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"requires": true,
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/estree": {
|
||||||
|
"version": "0.0.41",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.41.tgz",
|
||||||
|
"integrity": "sha512-rIAmXyJlqw4KEBO7+u9gxZZSQHaCNnIzYrnNmYVpgfJhxTqO0brCX0SYpqUTkVI5mwwUwzmtspLBGBKroMeynA=="
|
||||||
|
},
|
||||||
|
"@types/node": {
|
||||||
|
"version": "13.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.0.tgz",
|
||||||
|
"integrity": "sha512-zwrxviZS08kRX40nqBrmERElF2vpw4IUTd5khkhBTfFH8AOaeoLVx48EC4+ZzS2/Iga7NevncqnsUSYjM4OWYA=="
|
||||||
|
},
|
||||||
|
"acorn": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ=="
|
||||||
|
},
|
||||||
|
"rollup": {
|
||||||
|
"version": "1.27.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-1.27.14.tgz",
|
||||||
|
"integrity": "sha512-DuDjEyn8Y79ALYXMt+nH/EI58L5pEw5HU9K38xXdRnxQhvzUTI/nxAawhkAHUQeudANQ//8iyrhVRHJBuR6DSQ==",
|
||||||
|
"requires": {
|
||||||
|
"@types/estree": "0.0.41",
|
||||||
|
"@types/node": "13.1.0",
|
||||||
|
"acorn": "7.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
require('tailwindcss'),
|
||||||
|
require('autoprefixer')
|
||||||
|
]
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
R=function(e,n){function t(e,o,u,a){if(e.g)return o(e.e,e);var c=e.g=e.l,f=new XMLHttpRequest;f.onload=function(i,l){function s(){l--||o(n,e)}200==f.status||e.t?(i=[],(e.t=e.t||f.response).replace(/(\/\*[\w\W]*?\*\/|\/\/[^\n]*|[.$]r)|\brequire\s*\(\s*["']([^"']*)["']\s*\)/g,function(e,n,t){n||i.push(t)}),l=i.length,i.map(function(o){t(r(e.l,o),s,"."!=o[0]?c+"/../":n,o)}),s()):u?t(e.n=r(u+="../",a),o,u,a):(e.e=f,o(f,e))},e.t?f.onload():(f.open("GET",c,!0),f.send())}function r(e,n,t){if(e.e)throw e.e;return n?(f.href=e,i.href="."!=n[0]?"./node_modules/"+n:n,t=i.href+".js",f.href="",u[t]=u[t]||{l:t}):e.n?r(e.n):(e[c]||(e.f||a("(function(require,"+c+",module){"+e.t+"\n})//# sourceURL="+e.l))(function(n){return r(r(e.l,n))},e[c]={},e),e[c])}function o(e,n){t(e.call?{l:"",t:""+e,f:e}:r("",e),function(t,o){try{e=r(o)}catch(u){t=u}n&&n(t,e)})}var u={},a=eval,c="createElement",f=e[c]("base"),i=e[c]("a");return e.head.appendChild(f),c=e.querySelector("script[data-main]"),c&&o(c.dataset.main),c="exports",o}(document);
|
@ -0,0 +1,9 @@
|
|||||||
|
export default {
|
||||||
|
input: 'app_mithril.js',
|
||||||
|
//sourcemap: false,
|
||||||
|
//plugins,
|
||||||
|
output: {
|
||||||
|
file: '../public/bundle.js',
|
||||||
|
format: 'iife'
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,9 @@
|
|||||||
|
var util = {};
|
||||||
|
|
||||||
|
util.remove = function(arr, el){
|
||||||
|
var i=0;
|
||||||
|
while(arr[i] !== el){ i++; }
|
||||||
|
arr.splice(i,1)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default util;
|
@ -0,0 +1,5 @@
|
|||||||
|
function isArray(x){
|
||||||
|
return Array.isArray(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default isArray;
|
@ -0,0 +1,5 @@
|
|||||||
|
var isNumber = function(x){
|
||||||
|
return !isNaN(x);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default isNumber;
|
@ -0,0 +1,5 @@
|
|||||||
|
function isObject(x){
|
||||||
|
return (typeof x === 'object');
|
||||||
|
}
|
||||||
|
|
||||||
|
export default isObject;
|
@ -0,0 +1,5 @@
|
|||||||
|
var isUndefined = function(x){
|
||||||
|
return typeof(x)==="undefined";
|
||||||
|
}
|
||||||
|
|
||||||
|
export default isUndefined;
|
@ -0,0 +1,11 @@
|
|||||||
|
var remove = function(arr, pred){
|
||||||
|
var len = arr.length
|
||||||
|
for(var i=0; i<len; i++){
|
||||||
|
if(pred(arr[i], i)){
|
||||||
|
arr.splice(i,1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default remove;
|
@ -0,0 +1,5 @@
|
|||||||
|
var removeByIndex = function(arr, i){
|
||||||
|
arr.splice(i,1);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default removeByIndex;
|
@ -0,0 +1,11 @@
|
|||||||
|
var removeElement = function(arr, el){
|
||||||
|
var len = arr.length
|
||||||
|
for(var i=0; i<len; i++){
|
||||||
|
if(arr[i] === el){
|
||||||
|
arr.splice(i,1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default removeElement;
|
@ -0,0 +1,5 @@
|
|||||||
|
var toNumber = function(x){
|
||||||
|
return Number(x);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default toNumber;
|
@ -0,0 +1 @@
|
|||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="accusoft" class="svg-inline--fa fa-accusoft fa-w-20" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M322.1 252v-1l-51.2-65.8s-12 1.6-25 15.1c-9 9.3-242.1 239.1-243.4 240.9-7 10 1.6 6.8 15.7 1.7.8 0 114.5-36.6 114.5-36.6.5-.6-.1-.1.6-.6-.4-5.1-.8-26.2-1-27.7-.6-5.2 2.2-6.9 7-8.9l92.6-33.8c.6-.8 88.5-81.7 90.2-83.3zm160.1 120.1c13.3 16.1 20.7 13.3 30.8 9.3 3.2-1.2 115.4-47.6 117.8-48.9 8-4.3-1.7-16.7-7.2-23.4-2.1-2.5-205.1-245.6-207.2-248.3-9.7-12.2-14.3-12.9-38.4-12.8-10.2 0-106.8.5-116.5.6-19.2.1-32.9-.3-19.2 16.9C250 75 476.5 365.2 482.2 372.1zm152.7 1.6c-2.3-.3-24.6-4.7-38-7.2 0 0-115 50.4-117.5 51.6-16 7.3-26.9-3.2-36.7-14.6l-57.1-74c-5.4-.9-60.4-9.6-65.3-9.3-3.1.2-9.6.8-14.4 2.9-4.9 2.1-145.2 52.8-150.2 54.7-5.1 2-11.4 3.6-11.1 7.6.2 2.5 2 2.6 4.6 3.5 2.7.8 300.9 67.6 308 69.1 15.6 3.3 38.5 10.5 53.6 1.7 2.1-1.2 123.8-76.4 125.8-77.8 5.4-4 4.3-6.8-1.7-8.2z"></path></svg>
|
After Width: | Height: | Size: 1008 B |
@ -0,0 +1 @@
|
|||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="address-book" class="svg-inline--fa fa-address-book fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M436 160c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20V48c0-26.5-21.5-48-48-48H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h320c26.5 0 48-21.5 48-48v-48h20c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20v-64h20c6.6 0 12-5.4 12-12v-40c0-6.6-5.4-12-12-12h-20v-64h20zm-228-32c35.3 0 64 28.7 64 64s-28.7 64-64 64-64-28.7-64-64 28.7-64 64-64zm112 236.8c0 10.6-10 19.2-22.4 19.2H118.4C106 384 96 375.4 96 364.8v-19.2c0-31.8 30.1-57.6 67.2-57.6h5c12.3 5.1 25.7 8 39.8 8s27.6-2.9 39.8-8h5c37.1 0 67.2 25.8 67.2 57.6v19.2z"></path></svg>
|
After Width: | Height: | Size: 757 B |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
img.enlarged {
|
||||||
|
transition: transform 0.5s ease 0s;
|
||||||
|
transform: scale(1.5);
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
transition: transform 0.5s ease 0s;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
img.large-image {
|
||||||
|
position: fixed;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sph > select { width: min-content; }
|
||||||
|
|
||||||
|
body { overflow: auto; }
|
@ -0,0 +1,155 @@
|
|||||||
|
/* RGB */
|
||||||
|
@color1: rgba(34, 116, 165, 1);
|
||||||
|
@color2: rgba(34, 72, 112, 1);
|
||||||
|
@color3: rgba(163, 206, 241, 1);
|
||||||
|
@color4: rgba(231, 236, 239, 1);
|
||||||
|
@color5: rgba(48, 50, 56, 1);
|
||||||
|
|
||||||
|
/* Always show scrollarbar, so width of browser window doesn't change and refloaw content*/
|
||||||
|
html {overflow-y: scroll; font-size: 12pt;}
|
||||||
|
|
||||||
|
.overlay{
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0,0,0, 0.5);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.modal{
|
||||||
|
border: 2px black solid;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.messages-box{
|
||||||
|
position: fixed;
|
||||||
|
top: 5px;
|
||||||
|
|
||||||
|
/*display: flex;*/
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.messages-box > .error{
|
||||||
|
border: 1px red solid;
|
||||||
|
background-color: pink;
|
||||||
|
}
|
||||||
|
.messages-box > .notification{
|
||||||
|
border: 1px green solid;
|
||||||
|
background-color: lightgreen;
|
||||||
|
}
|
||||||
|
.messages-box > .error, .messages-box > .notification {
|
||||||
|
padding-left: 24px;
|
||||||
|
padding-right: 24px;
|
||||||
|
padding-top: 6px;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
}
|
||||||
|
/* Colors */
|
||||||
|
form {
|
||||||
|
input[type=text] {
|
||||||
|
outline: none;
|
||||||
|
border: 1px solid @color4;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: rgba(250, 252, 255, 1);
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
button.blue {
|
||||||
|
background-color: rgba(55, 139, 250, 1)
|
||||||
|
}
|
||||||
|
button.blue:active {
|
||||||
|
background-color: rgba(43, 122, 227, 1)
|
||||||
|
}
|
||||||
|
button.green {
|
||||||
|
background-color: rgba(91, 196, 4, 1)
|
||||||
|
}
|
||||||
|
button.green:active {
|
||||||
|
background-color: rgba(81, 166, 10, 1)
|
||||||
|
}
|
||||||
|
button.red {
|
||||||
|
background-color: rgba(240, 29, 57, 1)
|
||||||
|
}
|
||||||
|
button.red:active {
|
||||||
|
background-color: rgba(212, 23, 48, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Positioning */
|
||||||
|
|
||||||
|
.cart {
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
width: 90%;
|
||||||
|
border: 1px black solid;
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: white;
|
||||||
|
transition: right 0.3s ease-out;
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
background-color: @color1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.line-item-list{
|
||||||
|
list-style-type: none;
|
||||||
|
/*padding-inline-start: 10px;*/
|
||||||
|
.line-item {
|
||||||
|
/*display: grid;*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cart.hidden{
|
||||||
|
right: -90%;
|
||||||
|
transition: right 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
position:fixed;
|
||||||
|
width: 100%;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
transition: top 0.3s ease-out;
|
||||||
|
|
||||||
|
input{
|
||||||
|
display:block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.login-form.hidden {
|
||||||
|
top: -100px;
|
||||||
|
transition: top 0.3s ease-out;
|
||||||
|
}
|
||||||
|
.login-button {
|
||||||
|
}
|
||||||
|
.show-application-button{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Navigation Menu */
|
||||||
|
.navigation {
|
||||||
|
position:fixed;
|
||||||
|
width: 90%;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
background-color: grey;
|
||||||
|
transition: left 0.3s ease-out;
|
||||||
|
}
|
||||||
|
.navigation.hidden{
|
||||||
|
left: -90%;
|
||||||
|
transition: left 0.3s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For large screens: */
|
||||||
|
@media only screen and (min-width: 600px) {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
Font license info
|
||||||
|
|
||||||
|
|
||||||
|
## Typicons
|
||||||
|
|
||||||
|
(c) Stephen Hutchings 2012
|
||||||
|
|
||||||
|
Author: Stephen Hutchings
|
||||||
|
License: SIL (http://scripts.sil.org/OFL)
|
||||||
|
Homepage: http://typicons.com/
|
||||||
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
|||||||
|
This webfont is generated by http://fontello.com open source project.
|
||||||
|
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
Please, note, that you should obey original font licenses, used to make this
|
||||||
|
webfont pack. Details available in LICENSE.txt file.
|
||||||
|
|
||||||
|
- Usually, it's enough to publish content of LICENSE.txt file somewhere on your
|
||||||
|
site in "About" section.
|
||||||
|
|
||||||
|
- If your project is open-source, usually, it will be ok to make LICENSE.txt
|
||||||
|
file publicly available in your repository.
|
||||||
|
|
||||||
|
- Fonts, used in Fontello, don't require a clickable link on your site.
|
||||||
|
But any kind of additional authors crediting is welcome.
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
Comments on archive content
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
- /font/* - fonts in different formats
|
||||||
|
|
||||||
|
- /css/* - different kinds of css, for all situations. Should be ok with
|
||||||
|
twitter bootstrap. Also, you can skip <i> style and assign icon classes
|
||||||
|
directly to text elements, if you don't mind about IE7.
|
||||||
|
|
||||||
|
- demo.html - demo file, to show your webfont content
|
||||||
|
|
||||||
|
- LICENSE.txt - license info about source fonts, used to build your one.
|
||||||
|
|
||||||
|
- config.json - keeps your settings. You can import it back into fontello
|
||||||
|
anytime, to continue your work
|
||||||
|
|
||||||
|
|
||||||
|
Why so many CSS files ?
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Because we like to fit all your needs :)
|
||||||
|
|
||||||
|
- basic file, <your_font_name>.css - is usually enough, it contains @font-face
|
||||||
|
and character code definitions
|
||||||
|
|
||||||
|
- *-ie7.css - if you need IE7 support, but still don't wish to put char codes
|
||||||
|
directly into html
|
||||||
|
|
||||||
|
- *-codes.css and *-ie7-codes.css - if you like to use your own @font-face
|
||||||
|
rules, but still wish to benefit from css generation. That can be very
|
||||||
|
convenient for automated asset build systems. When you need to update font -
|
||||||
|
no need to manually edit files, just override old version with archive
|
||||||
|
content. See fontello source code for examples.
|
||||||
|
|
||||||
|
- *-embedded.css - basic css file, but with embedded WOFF font, to avoid
|
||||||
|
CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain.
|
||||||
|
We strongly recommend to resolve this issue by `Access-Control-Allow-Origin`
|
||||||
|
server headers. But if you ok with dirty hack - this file is for you. Note,
|
||||||
|
that data url moved to separate @font-face to avoid problems with <IE9, when
|
||||||
|
string is too long.
|
||||||
|
|
||||||
|
- animate.css - use it to get ideas about spinner rotation animation.
|
||||||
|
|
||||||
|
|
||||||
|
Attention for server setup
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
You MUST setup server to reply with proper `mime-types` for font files -
|
||||||
|
otherwise some browsers will fail to show fonts.
|
||||||
|
|
||||||
|
Usually, `apache` already has necessary settings, but `nginx` and other
|
||||||
|
webservers should be tuned. Here is list of mime types for our file extensions:
|
||||||
|
|
||||||
|
- `application/vnd.ms-fontobject` - eot
|
||||||
|
- `application/x-font-woff` - woff
|
||||||
|
- `application/x-font-ttf` - ttf
|
||||||
|
- `image/svg+xml` - svg
|
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"css_prefix_text": "icon-",
|
||||||
|
"css_use_suffix": false,
|
||||||
|
"hinting": true,
|
||||||
|
"units_per_em": 1000,
|
||||||
|
"ascent": 850,
|
||||||
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"uid": "e0d15ef5945000f5f264acc35494002f",
|
||||||
|
"css": "basket",
|
||||||
|
"code": 59392,
|
||||||
|
"src": "typicons"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
Animation example, for spinners
|
||||||
|
*/
|
||||||
|
.animate-spin {
|
||||||
|
-moz-animation: spin 2s infinite linear;
|
||||||
|
-o-animation: spin 2s infinite linear;
|
||||||
|
-webkit-animation: spin 2s infinite linear;
|
||||||
|
animation: spin 2s infinite linear;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
@-moz-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-o-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-moz-transform: rotate(359deg);
|
||||||
|
-o-transform: rotate(359deg);
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-o-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-moz-transform: rotate(359deg);
|
||||||
|
-o-transform: rotate(359deg);
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-o-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-o-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-moz-transform: rotate(359deg);
|
||||||
|
-o-transform: rotate(359deg);
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-ms-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-o-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-moz-transform: rotate(359deg);
|
||||||
|
-o-transform: rotate(359deg);
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
-moz-transform: rotate(0deg);
|
||||||
|
-o-transform: rotate(0deg);
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
-moz-transform: rotate(359deg);
|
||||||
|
-o-transform: rotate(359deg);
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
|
transform: rotate(359deg);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
.icon-basket:before { content: '\e800'; } /* '' */
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
.icon-basket { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
@ -0,0 +1,13 @@
|
|||||||
|
[class^="icon-"], [class*=" icon-"] {
|
||||||
|
font-family: 'fontello';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
|
||||||
|
/* fix buttons height */
|
||||||
|
line-height: 1em;
|
||||||
|
|
||||||
|
/* you can be more comfortable with increased icons size */
|
||||||
|
/* font-size: 120%; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-basket { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
@ -0,0 +1,58 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'fontello';
|
||||||
|
src: url('../font/fontello.eot?35157520');
|
||||||
|
src: url('../font/fontello.eot?35157520#iefix') format('embedded-opentype'),
|
||||||
|
url('../font/fontello.woff2?35157520') format('woff2'),
|
||||||
|
url('../font/fontello.woff?35157520') format('woff'),
|
||||||
|
url('../font/fontello.ttf?35157520') format('truetype'),
|
||||||
|
url('../font/fontello.svg?35157520#fontello') format('svg');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
|
||||||
|
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
|
||||||
|
/*
|
||||||
|
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||||
|
@font-face {
|
||||||
|
font-family: 'fontello';
|
||||||
|
src: url('../font/fontello.svg?35157520#fontello') format('svg');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
[class^="icon-"]:before, [class*=" icon-"]:before {
|
||||||
|
font-family: "fontello";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
speak: none;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: inherit;
|
||||||
|
width: 1em;
|
||||||
|
margin-right: .2em;
|
||||||
|
text-align: center;
|
||||||
|
/* opacity: .8; */
|
||||||
|
|
||||||
|
/* For safety - reset parent styles, that can break glyph codes*/
|
||||||
|
font-variant: normal;
|
||||||
|
text-transform: none;
|
||||||
|
|
||||||
|
/* fix buttons height, for twitter bootstrap */
|
||||||
|
line-height: 1em;
|
||||||
|
|
||||||
|
/* Animation center compensation - margins should be symmetric */
|
||||||
|
/* remove if not needed */
|
||||||
|
margin-left: .2em;
|
||||||
|
|
||||||
|
/* you can be more comfortable with increased icons size */
|
||||||
|
/* font-size: 120%; */
|
||||||
|
|
||||||
|
/* Font smoothing. That was taken from TWBS */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
/* Uncomment for 3D effect */
|
||||||
|
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-basket:before { content: '\e800'; } /* '' */
|
@ -0,0 +1,306 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><!--[if lt IE 9]><script language="javascript" type="text/javascript" src="//html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
|
||||||
|
<meta charset="UTF-8"><style>/*
|
||||||
|
* Bootstrap v2.2.1
|
||||||
|
*
|
||||||
|
* Copyright 2012 Twitter, Inc
|
||||||
|
* Licensed under the Apache License v2.0
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Designed and built with all the love in the world @twitter by @mdo and @fat.
|
||||||
|
*/
|
||||||
|
.clearfix {
|
||||||
|
*zoom: 1;
|
||||||
|
}
|
||||||
|
.clearfix:before,
|
||||||
|
.clearfix:after {
|
||||||
|
display: table;
|
||||||
|
content: "";
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
.clearfix:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
font-size: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
a:focus {
|
||||||
|
outline: thin dotted #333;
|
||||||
|
outline: 5px auto -webkit-focus-ring-color;
|
||||||
|
outline-offset: -2px;
|
||||||
|
}
|
||||||
|
a:hover,
|
||||||
|
a:active {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
button,
|
||||||
|
input {
|
||||||
|
*overflow: visible;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
input::-moz-focus-inner {
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
color: #333;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #08c;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: #005580;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
margin-left: -20px;
|
||||||
|
*zoom: 1;
|
||||||
|
}
|
||||||
|
.row:before,
|
||||||
|
.row:after {
|
||||||
|
display: table;
|
||||||
|
content: "";
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
.row:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
[class*="span"] {
|
||||||
|
float: left;
|
||||||
|
min-height: 1px;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
.container,
|
||||||
|
.navbar-static-top .container,
|
||||||
|
.navbar-fixed-top .container,
|
||||||
|
.navbar-fixed-bottom .container {
|
||||||
|
width: 940px;
|
||||||
|
}
|
||||||
|
.span12 {
|
||||||
|
width: 940px;
|
||||||
|
}
|
||||||
|
.span11 {
|
||||||
|
width: 860px;
|
||||||
|
}
|
||||||
|
.span10 {
|
||||||
|
width: 780px;
|
||||||
|
}
|
||||||
|
.span9 {
|
||||||
|
width: 700px;
|
||||||
|
}
|
||||||
|
.span8 {
|
||||||
|
width: 620px;
|
||||||
|
}
|
||||||
|
.span7 {
|
||||||
|
width: 540px;
|
||||||
|
}
|
||||||
|
.span6 {
|
||||||
|
width: 460px;
|
||||||
|
}
|
||||||
|
.span5 {
|
||||||
|
width: 380px;
|
||||||
|
}
|
||||||
|
.span4 {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
.span3 {
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
|
.span2 {
|
||||||
|
width: 140px;
|
||||||
|
}
|
||||||
|
.span1 {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
[class*="span"].pull-right,
|
||||||
|
.row-fluid [class*="span"].pull-right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
*zoom: 1;
|
||||||
|
}
|
||||||
|
.container:before,
|
||||||
|
.container:after {
|
||||||
|
display: table;
|
||||||
|
content: "";
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
.container:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin: 0 0 10px;
|
||||||
|
}
|
||||||
|
.lead {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 21px;
|
||||||
|
font-weight: 200;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
small {
|
||||||
|
font-size: 85%;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
margin: 10px 0;
|
||||||
|
font-family: inherit;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 20px;
|
||||||
|
color: inherit;
|
||||||
|
text-rendering: optimizelegibility;
|
||||||
|
}
|
||||||
|
h1 small {
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 1;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 38.5px;
|
||||||
|
}
|
||||||
|
h1 small {
|
||||||
|
font-size: 24.5px;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin-top: 90px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -480px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
padding-top: 10px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
color: #ddd;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.footer a {
|
||||||
|
color: #ccc;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.the-icons {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
.switch {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 10px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.switch input {
|
||||||
|
margin-right: 0.3em;
|
||||||
|
}
|
||||||
|
.codesOn .i-name {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.codesOn .i-code {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.i-code {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'fontello';
|
||||||
|
src: url('./font/fontello.eot?30559621');
|
||||||
|
src: url('./font/fontello.eot?30559621#iefix') format('embedded-opentype'),
|
||||||
|
url('./font/fontello.woff?30559621') format('woff'),
|
||||||
|
url('./font/fontello.ttf?30559621') format('truetype'),
|
||||||
|
url('./font/fontello.svg?30559621#fontello') format('svg');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.demo-icon
|
||||||
|
{
|
||||||
|
font-family: "fontello";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
speak: none;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: inherit;
|
||||||
|
width: 1em;
|
||||||
|
margin-right: .2em;
|
||||||
|
text-align: center;
|
||||||
|
/* opacity: .8; */
|
||||||
|
|
||||||
|
/* For safety - reset parent styles, that can break glyph codes*/
|
||||||
|
font-variant: normal;
|
||||||
|
text-transform: none;
|
||||||
|
|
||||||
|
/* fix buttons height, for twitter bootstrap */
|
||||||
|
line-height: 1em;
|
||||||
|
|
||||||
|
/* Animation center compensation - margins should be symmetric */
|
||||||
|
/* remove if not needed */
|
||||||
|
margin-left: .2em;
|
||||||
|
|
||||||
|
/* You can be more comfortable with increased icons size */
|
||||||
|
/* font-size: 120%; */
|
||||||
|
|
||||||
|
/* Font smoothing. That was taken from TWBS */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
/* Uncomment for 3D effect */
|
||||||
|
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<link rel="stylesheet" href="css/animation.css"><!--[if IE 7]><link rel="stylesheet" href="css/" + font.fontname + "-ie7.css"><![endif]-->
|
||||||
|
<script>
|
||||||
|
function toggleCodes(on) {
|
||||||
|
var obj = document.getElementById('icons');
|
||||||
|
|
||||||
|
if (on) {
|
||||||
|
obj.className += ' codesOn';
|
||||||
|
} else {
|
||||||
|
obj.className = obj.className.replace(' codesOn', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container header">
|
||||||
|
<h1>fontello <small>font demo</small></h1>
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" onclick="toggleCodes(this.checked)">show codes
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="container" id="icons">
|
||||||
|
<div class="row">
|
||||||
|
<div class="the-icons span3" title="Code: 0xe800"><i class="demo-icon icon-basket"></i> <span class="i-name">icon-basket</span><span class="i-code">0xe800</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="container footer">Generated by <a href="http://fontello.com">fontello.com</a></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue