Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
swap-api/swap-api/templates/index.phtml
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
460 lines (385 sloc)
16.4 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta content="width=device-width,initial-scale=1,minimal-ui" name="viewport"> | |
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic|Material+Icons"> | |
<link rel="stylesheet" href="https://unpkg.com/vue-material@beta/dist/vue-material.min.css"> | |
<link rel="stylesheet" href="https://unpkg.com/vue-material@beta/dist/theme/default.css"> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> | |
<style> | |
.Red { | |
background-color:red!important; | |
} | |
.Red { | |
color:white!important; | |
} | |
.Yellow{ | |
background-color:yellow!important; | |
} | |
.Yellow * { | |
color:brown!important; | |
} | |
.Green{ | |
background-color:green!important; | |
} | |
.Green * { | |
color:white!important; | |
} | |
.scn-target { | |
height:160px; | |
width:200px; | |
top:120px; | |
left:50%; | |
margin-left:-100px; | |
border:3px solid red; | |
position:absolute; | |
} | |
canvas.drawing, canvas.drawingBuffer { | |
position: absolute; | |
left: 0; | |
top: 0; | |
} | |
</style> | |
<title>SWAP / WellSCAN Barcode Lookup</title> | |
</head> | |
<body> | |
<div id="app"> | |
<template> | |
<div class="page-container"> | |
<md-dialog :md-active.sync="showDialog" @md-opened = "theScan"> | |
<div id="scanner-container"> | |
<div class="scn-target"></div> | |
</div> | |
<md-dialog-actions> | |
<md-button class="md-primary" @click="killScan">Close</md-button> | |
</md-dialog-actions> | |
</md-dialog> | |
<md-app> | |
<md-app-toolbar class="md-primary"> | |
<md-button v-on:click = "showSettings = true" class="md-icon-button"> | |
<md-icon>settings</md-icon> | |
</md-button> | |
<span style="flex:1;" class="md-title">WellSCAN (SWAP Food Lookup)</span> | |
<md-button v-if = "this.particpantId" v-on:click = "showCart = true" class="md-icon-button"> | |
<md-icon>shopping_cart</md-icon> | |
</md-button> | |
</md-app-toolbar> | |
<md-app-content> | |
<md-card> | |
<md-card-header> | |
<div class="md-title">Search for a Food by UPC</div> | |
</md-card-header> | |
<md-card-content> | |
<md-field> | |
<label>Enter a UPC</label> | |
<md-input ref="searchBox" v-focus v-on:focus = "clearAndFocus()" v-on:keyup.enter="getData" id="searchTerm" v-model="searchTerm" placeholder="Enter UPC"></md-input> | |
<md-button v-if="searchTerm" v-on:click = "searchTerm = ''; clearAndFocus();" title="Clear"><md-icon > clear</md-icon></md-button> | |
<md-button v-on:click = "showDialog = true" title="Scan Barcode">[ <i class="fa fa-barcode"></i> ]</md-button> | |
</md-field> | |
<div class="notFound md-accent" v-if="notFound"> | |
<div>Hmm...that food wasn't in SWAP Global. Enter a category to look it up.</div> | |
<md-field> | |
<label for="category">SWAP Category</label> | |
<md-select v-model="rulesCat" name="category"> | |
<md-option value="1">Fruit</md-option> | |
<md-option value="2">Vegetables</md-option> | |
<md-option value="3">Grains</md-option> | |
<md-option value="4">Protein: Plant-Based</md-option> | |
<md-option value="5">Protein: Animal</md-option> | |
<md-option value="6">Combination Foods/Meals</md-option> | |
<md-option value="7">Dairy - Milk</md-option> | |
<md-option value="8">Dairy - Yogurt</md-option> | |
<md-option value="9">Dairy - Cheese</md-option> | |
<md-option value="10">Condiments</md-option> | |
<md-option value="11">Beverages</md-option> | |
<md-option value="12">Snacks/Desserts</md-option> | |
</md-select> | |
</md-field> | |
</div> | |
</md-card-content> | |
<md-card-actions> | |
<md-button type="submit" v-on:click="getData">Search</md-button> | |
</md-card-actions> | |
</md-card> | |
<md-card v-if="showSearchResults" :class="[food.rank.name]"> | |
<md-card-header> | |
<div :class="['md-title']">{{food.food.name}}</div> | |
</md-card-header> | |
<md-card-content> | |
<p>({{food.food.barcode}})</p> | |
<p>{{food.category.name}}</p> | |
<p>{{food.rank.name}}</p> | |
</md-card-content> | |
<md-card-actions> | |
<md-button v-if = "this.particpantId" v-on:click = "addToCart(food)" class="md-icon-button"> | |
<md-icon style="color:#fff;" > add_shopping_cart</md-icon> | |
</md-button> | |
</md-card-actions> | |
</md-card> | |
<md-empty-state v-if="!searchTerm" | |
md-icon="search" | |
md-label="Search for a Food by UPC" | |
md-description="When you search for a food via UPC, search results will show up here."> | |
</md-empty-state> | |
<md-snackbar md-position="center" :md-active.sync="showNotFoundWarning"> | |
<span>Hmm...that food wasn't in SWAP Global. Enter a category to look it up.</span> | |
</md-snackbar> | |
<md-snackbar md-position="center" :md-active.sync="showAddedToCartNotice"> | |
<span>Item added to cart!</span> | |
</md-snackbar> | |
<md-card v-if = "this.errorMSG" class="md-accent" md-with-hover> | |
<md-ripple> | |
<md-card-header> | |
<div class="md-title">Error!</div> | |
<p>But you can add it to the cart anyway!</p> | |
<md-button v-if = "this.particpantId" v-on:click = "addUPCToCart(searchTerm)" class="md-icon-button"> | |
<md-icon style="color:#fff;" > add_shopping_cart</md-icon> | |
</md-button> | |
</md-card-header> | |
<md-card-content> | |
{{this.errorMSG}} | |
</md-card-content> | |
<md-card-actions> | |
<md-button v-on:click="errorMSG = false">Dismiss</md-button> | |
</md-card-actions> | |
</md-ripple> | |
</md-card> | |
<md-dialog :md-active.sync="showSettings"> | |
<md-dialog-title>Settings</md-dialog-title> | |
<md-dialog-content> | |
<md-field> | |
<label>Participant ID</label> | |
<md-input v-model="particpantId"></md-input> | |
</md-field> | |
<div> | |
<label style="text-align:center;"><strong>Empty Cart?</strong></label> <br> | |
<md-button class="md-accent" @click="cart = []">Empty Cart</md-button> | |
</div> | |
</md-dialog-content> | |
<md-dialog-actions> | |
<md-button class="md-primary" @click="showSettings = false">Close</md-button> | |
</md-dialog-actions> | |
</md-dialog> | |
<md-dialog :md-active.sync="showCart"> | |
<md-dialog-title>Shopping Cart</md-dialog-title> | |
<md-dialog-content> | |
<md-table> | |
<md-table-row> | |
<md-table-head>Food</md-table-head> | |
<md-table-head>Rank</md-table-head> | |
<md-table-head>Remove</md-table-head> | |
</md-table-row> | |
<md-table-row v-for="(purchase, index) in cart" :class = "[purchase.rank]"> | |
<md-table-cell>{{purchase.name}}</md-table-cell> | |
<md-table-cell>{{purchase.rank}}</md-table-cell> | |
<md-table-cell> | |
<md-button v-on:click = "removeItem(index)" class="md-icon-button"> | |
<md-icon>remove_shopping_cart</md-icon> | |
</md-button> | |
</md-table-cell> | |
</md-table-row> | |
</md-table> | |
</md-dialog-content> | |
<md-dialog-actions> | |
<md-button class="md-primary" @click="showCart = false">Close</md-button> | |
</md-dialog-actions> | |
</md-dialog> | |
</md-app-content> | |
</md-app> | |
</div> | |
</template> | |
</div> | |
<script src="https://webrtc.github.io/adapter/adapter-latest.js" type="text/javascript"></script> | |
<script src="https://cdn.rawgit.com/serratus/quaggaJS/0420d5e0/dist/quagga.min.js"></script> | |
<script src="https://unpkg.com/vue"></script> | |
<script src="https://unpkg.com/vue-material"></script> | |
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> | |
<script> | |
Vue.use(VueMaterial.default); | |
let app = new Vue({ | |
el: '#app', | |
data() { | |
return { | |
food:{}, | |
searchTerm:null, | |
notFound: false, | |
rulesCat:null, | |
showNotFoundWarning:false, | |
showAddedToCartNotice:false, | |
showSettings:false, | |
showCart:false, | |
showDialog : false, | |
particpantId : "", | |
cart : [], | |
showSearchResults: false, | |
errorMSG: null | |
} | |
}, | |
directives: { | |
focus: { | |
// directive definition | |
inserted: function (el) { | |
el.focus() | |
} | |
} | |
}, | |
methods: { | |
killScan: function() { | |
this.showDialog = false | |
Quagga.stop(); | |
}, | |
clearAndFocus() { | |
this.$refs.searchBox.$el.focus(); | |
this.searchTerm = null; | |
this.showSearchResults = false; | |
}, | |
addToCart(food) { | |
if (this.particpantId) { | |
let randId = '_' + Math.random().toString(36).substr(2, 9); | |
let that = this; | |
let upc = food.food.barcode; | |
let particpantId = this.particpantId; | |
this.cart.push({randId: randId, name:food.food.name,rank:food.rank.name}); | |
axios.get('/purchase/add/' + particpantId + "/" + upc + "/" + randId).then((response) => { | |
}, (error) => { | |
console.log(error); | |
}); | |
//this.showCart = true; | |
this.showAddedToCartNotice = true; | |
} else { | |
alert('Please set your Partcipant ID before adding an item to your cart.') | |
} | |
}, | |
addUPCToCart(upc){ | |
let dummyFood = { | |
food: { | |
name:"Unknown Food", | |
barcode:upc | |
}, | |
rank: { | |
name:"Rank Unknown" | |
} | |
}; | |
this.addToCart(dummyFood); | |
}, | |
removeItem(index){ | |
console.log("should remove " + index); | |
let food = this.cart[index]; | |
// hit the API to remove a purchase | |
axios.get('/purchase/remove/' + food.randId).then((response) => {}, (error) => { | |
console.log(error); | |
}); | |
this.cart.splice(index, 1); | |
}, | |
getData: function(event) { | |
// if we're not looking up a new food | |
if (!this.notFound) { | |
axios.get('/food/fromSWAPGlobal/' + this.searchTerm).then((response) => { | |
if(response.data.status != "notFound") { | |
this.food = response.data; | |
this.food.id = response.data.food.id; | |
this.showSearchResults = true; | |
} | |
if (response.data.status == "notFound") { | |
this.notFound = true; | |
this.showNotFoundWarning = true; | |
} | |
}, (error) => { | |
this.loading = false; | |
}) | |
} else { // if we're looking up a new food (not found in swap db) | |
axios.get('/food/runLookup/' + this.searchTerm + "/" + this.rulesCat).then((response) => { | |
this.food = response.data; | |
if(response.data.status != "notFound") { | |
this.food.id = this.food.food.id; | |
this.notFound = false; | |
this.showSearchResults = true; | |
} else { | |
this.errorMSG = response.data.msg; | |
} | |
}, (error) => { | |
this.loading = false; | |
}) | |
} | |
}, | |
initScanner: () => { | |
console.log("wut"); | |
this.showDialog = true; | |
}, | |
theScan: () => { | |
console.log('ummm'); | |
startScanner(); | |
} | |
} | |
}) | |
var _scannerIsRunning = false; | |
function startScanner() { | |
Quagga.init({ | |
inputStream: { | |
name: "Live", | |
type: "LiveStream", | |
target: document.querySelector('#scanner-container'), | |
constraints: { | |
width: 480, | |
height: 320, | |
facingMode: "environment" | |
}, | |
}, | |
decoder: { | |
readers: [ | |
'code_128_reader', | |
'ean_8_reader', | |
'upc_reader', | |
'upc_e_reader' | |
], | |
halfSample: true, | |
patchSize: "medium", | |
debug: { | |
drawBoundingBox: true, | |
showFrequency: true, | |
drawScanline: true, | |
showPattern: true | |
}, | |
multiple:false | |
}, | |
}, function (err) { | |
if (err) { | |
console.log(err); | |
return | |
} | |
console.log("Initialization finished. Ready to start"); | |
Quagga.start(); | |
// Set flag to is running | |
_scannerIsRunning = true; | |
}); | |
Quagga.onProcessed(function (result) { | |
var drawingCtx = Quagga.canvas.ctx.overlay, | |
drawingCanvas = Quagga.canvas.dom.overlay; | |
if (result) { | |
if (result.boxes) { | |
drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height"))); | |
result.boxes.filter(function (box) { | |
return box !== result.box; | |
}).forEach(function (box) { | |
Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, { color: "green", lineWidth: 2 }); | |
}); | |
} | |
if (result.box) { | |
Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: "#00F", lineWidth: 2 }); | |
} | |
if (result.codeResult && result.codeResult.code) { | |
Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: 'red', lineWidth: 3 }); | |
} | |
} | |
}); | |
Quagga.onDetected(function (result) { | |
console.log("Barcode detected and processed : [" + result.codeResult.code + "]", result); | |
Quagga.stop(); | |
app.searchTerm = result.codeResult.code; | |
app.showDialog = false; | |
}); | |
} | |
</script> | |
</body> | |
</html> |