13 Commits

Author SHA1 Message Date
6c7bb9eff4 Order Screen fully ported to Giraffe View Engine 2022-07-02 14:22:52 +10:00
905adcd7bd Migration test data complete 2022-07-01 15:25:10 +10:00
5e78701b0b Buttons now render entirely in Giraffe 2022-06-30 23:43:16 +10:00
420c6530e0 Lost source code, switching back to main branch 2022-06-29 22:03:45 +10:00
100a772297 Updates to Order Screen 2022-05-12 20:03:39 +10:00
a587423d3e view progression 2022-03-07 21:36:38 +10:00
cc7d06e78b Change to background image loader 2022-02-27 11:57:52 +10:00
05a1a71e6b CSS background in quotes 2022-02-26 22:31:59 +10:00
dredgy
b6aadc072f Merge pull request #7 from dredgy/installer
Migration system added.
2022-02-26 22:24:07 +10:00
207edf0de3 Migration system added.
Install scripts for database schema and dummy data too.
2022-02-26 22:23:30 +10:00
dredgy
6439b4326c Merge pull request #6 from dredgy/add_view_engine
Moved to Giraffe View Engine
2022-02-22 15:23:22 +10:00
cb58262507 Moved to Giraffe View Engine 2022-02-22 15:22:32 +10:00
dredgy
b5a2514495 Merge pull request #5 from dredgy/npm_scripts
Npm scripts
2022-02-14 19:04:54 +10:00
173 changed files with 1371 additions and 1715 deletions

View File

@@ -1,16 +1,15 @@
module DredgePos.Authenticate.Controller module DredgePos.Authenticate.Controller
open Giraffe
open DredgeFramework open DredgeFramework
open Microsoft.AspNetCore.Http open Microsoft.AspNetCore.Http
open DredgePos.Global.Controller
let loadAuthenticatePage (): HttpHandler = let loadAuthenticatePage =
let variables = map ["title", "Log In"] let scripts = [|"dredgepos.authenticate.js"|] |> addDefaultScripts
let scripts = ["dredgepos.authenticate.js"] let styles = [|"dredgepos.authenticate.css"|] |> addDefaultStyles
let styles = ["dredgepos.authenticate.css"] let metaTags = [|"viewport", "user-scalable = no, initial-scale=0.8,maximum-scale=0.8 ,shrink-to-fit=yes"|] |> addDefaultMetaTags
Theme.loadTemplateWithVarsScriptsAndStyles "authenticate" variables scripts styles View.index scripts styles metaTags
|> htmlString
let loginWithLoginCode (context: HttpContext) (login_code: int) = let loginWithLoginCode (context: HttpContext) (login_code: int) =
if Model.clerkLogin login_code context then ajaxSuccess "success" if Model.clerkLogin login_code context then ajaxSuccess "success"

View File

@@ -11,10 +11,10 @@ let getClerkByLoginCode (loginCode: int) =
let clerk = let clerk =
select { select {
table "clerks" table "clerks"
where (eq "clerk_login_code" loginCode) where (eq "login_code" loginCode)
take 1 take 1
} }
|> db.Select<clerk> |> Database.Select<clerk>
|> EnumerableToArray |> EnumerableToArray
if (clerk |> length) > 0 then if (clerk |> length) > 0 then
@@ -26,19 +26,19 @@ let deleteSession sessionId context =
delete { delete {
table "sessions" table "sessions"
where (eq "session_id" sessionId) where (eq "session_id" sessionId)
} |> db.Delete |> ignore } |> Database.Delete |> ignore
Browser.deleteCookie "dredgepos_clerk_logged_in" context Browser.deleteCookie "dredgepos_clerk_logged_in" context
let deleteSessionByClerkId clerk_id context = let deleteSessionByClerkId clerk_id context =
delete { delete {
table "sessions" table "sessions"
where (eq "clerk_id" clerk_id) where (eq "clerk_id" clerk_id)
} |> db.Delete |> ignore } |> Database.Delete |> ignore
Browser.deleteCookie "dredgepos_clerk_logged_in" context Browser.deleteCookie "dredgepos_clerk_logged_in" context
let createNewSession (clerk: clerk) context = let createNewSession (clerk: clerk) context =
if (getClerkByLoginCode clerk.clerk_login_code).IsSome then if (getClerkByLoginCode clerk.login_code).IsSome then
deleteSessionByClerkId clerk.id context deleteSessionByClerkId clerk.id context
let newSessionId = (Guid.NewGuid().ToString "N") + (Guid.NewGuid().ToString "N") let newSessionId = (Guid.NewGuid().ToString "N") + (Guid.NewGuid().ToString "N")
@@ -53,18 +53,14 @@ let createNewSession (clerk: clerk) context =
table "sessions" table "sessions"
value newSession value newSession
} }
|> db.Insert |> Database.Insert
|> ignore |> ignore
Browser.setCookie "dredgepos_clerk_logged_in" newSessionId (DateTimeOffset.UtcNow.AddHours(24.0)) context Browser.setCookie "dredgepos_clerk_logged_in" newSessionId (DateTimeOffset.UtcNow.AddHours(24.0)) context
let sessionExists (sessionId: string) context = let sessionExists (sessionId: string) context =
let sessions = let sessions = Entity.GetAllByColumn<session> "session_id" sessionId
select {
table "sessions"
where (eq "session_id" sessionId)
} |> db.Select<session>
match sessions |> length with match sessions |> length with
| 0 -> false | 0 -> false
@@ -78,11 +74,11 @@ let sessionExists (sessionId: string) context =
false false
let checkAuthentication clerk = let checkAuthentication clerk =
let existingClerk = getClerkByLoginCode clerk.clerk_login_code let existingClerk = getClerkByLoginCode clerk.login_code
existingClerk.IsSome existingClerk.IsSome
&& existingClerk.Value.id = clerk.id && existingClerk.Value.id = clerk.id
&& existingClerk.Value.clerk_name = clerk.clerk_name && existingClerk.Value.name = clerk.name
&& existingClerk.Value.clerk_login_code = clerk.clerk_login_code && existingClerk.Value.login_code = clerk.login_code
let getLoginCookie context = Browser.getCookie "dredgepos_clerk_logged_in" context let getLoginCookie context = Browser.getCookie "dredgepos_clerk_logged_in" context
@@ -91,7 +87,7 @@ let getSession (sessionId: string) =
select { select {
table "sessions" table "sessions"
where (eq "session_id" sessionId) where (eq "session_id" sessionId)
} |> db.Select<session> } |> Database.Select<session>
match sessions |> length with match sessions |> length with
| 0 -> {session_id = ""; clerk_json = ""; clerk_id= 0; expires= 0; id=0} | 0 -> {session_id = ""; clerk_json = ""; clerk_id= 0; expires= 0; id=0}
@@ -99,7 +95,7 @@ let getSession (sessionId: string) =
let getCurrentClerk context = let getCurrentClerk context =
let cookie = getLoginCookie context let cookie = getLoginCookie context
let emptyClerk = {id=0; clerk_login_code=0; clerk_usergroup=0; clerk_name=""} let emptyClerk = {id=0; login_code=0; user_group_id=0; name=""}
match cookie with match cookie with
| "" -> | "" ->
Browser.redirect "/login" context Browser.redirect "/login" context

View File

@@ -3,7 +3,7 @@
open Saturn open Saturn
open Giraffe open Giraffe
let homepage = (warbler (fun _ -> Controller.loadAuthenticatePage() )) let homepage = (warbler (fun _ -> htmlView Controller.loadAuthenticatePage ))
let handlePostRoute<'a> handlerFunction post next ctx = json (handlerFunction ctx post) next ctx let handlePostRoute<'a> handlerFunction post next ctx = json (handlerFunction ctx post) next ctx
let pipeline = pipeline{ let pipeline = pipeline{

10
Authenticate/View.fs Normal file
View File

@@ -0,0 +1,10 @@
module DredgePos.Authenticate.View
open DredgePos.Global.View
open Giraffe.ViewEngine
let content = div [_id "authenticator"] []
let index scripts styles metaTags = HtmlPage "Floorplan" (GetScripts scripts) (GetStyles styles) (GetMetaTags metaTags) [|content|]

View File

@@ -25,5 +25,4 @@ let setCookie name value (expiry: DateTimeOffset) (context: HttpContext) =
options.Expires <- expiry options.Expires <- expiry
context.Response.Cookies.Append(name, value, options); context.Response.Cookies.Append(name, value, options);
let redirect url (context: HttpContext) = let redirect url (context: HttpContext) = context.Response.Redirect url
context.Response.Redirect url

View File

@@ -1,46 +1,98 @@
module db module Database
open Dapper open Dapper
open Dapper.FSharp
open Dapper.FSharp.PostgreSQL open Dapper.FSharp.PostgreSQL
open DredgeFramework open DredgeFramework
open DredgePos.Types
open Npgsql
let connString = "Server=localhost;Port=5432;User Id=postgres;Password=root;Database=dredgepos;Include Error Detail=true"
//let connString = "server=localhost;uid=root;pwd=;database=dredgepos;table cache = false" let connect connectionString = new NpgsqlConnection(connectionString)
let connection = new Npgsql.NpgsqlConnection(connString)
let getDatabaseSettings () = (getConfig ()).database
let getConnectionString () =
let db = getDatabaseSettings ()
$"Server={db.host};Port={db.port};User Id={db.username};Password={db.password};Database={db.db_name};Include Error Detail=true"
let connectToDatabase () = connect (getConnectionString ())
let closeAndReturn (connection: NpgsqlConnection) (result: 'a) =
connection.Dispose()
result
let Select<'a> asyncQuery = let Select<'a> asyncQuery =
let connection = connectToDatabase ()
asyncQuery asyncQuery
|> connection.SelectAsync<'a> |> connection.SelectAsync<'a>
|> RunSynchronously |> RunSynchronously
|> EnumerableToArray |> EnumerableToArray
|> closeAndReturn connection
let SelectJoin<'a, 'b> asyncQuery = let SelectJoin<'a, 'b> asyncQuery =
let connection = connectToDatabase ()
asyncQuery asyncQuery
|> connection.SelectAsync<'a, 'b> |> connection.SelectAsync<'a, 'b>
|> RunSynchronously |> RunSynchronously
|> EnumerableToArray |> EnumerableToArray
|> closeAndReturn connection
let Insert<'a> asyncQuery = let Insert<'a> asyncQuery =
let connection = connectToDatabase ()
asyncQuery asyncQuery
|> connection.InsertAsync<'a> |> connection.InsertAsync<'a>
|> RunSynchronously |> RunSynchronously
|> closeAndReturn connection
let InsertOutput<'a> asyncQuery = let InsertOutput<'a> asyncQuery =
let connection = connectToDatabase ()
asyncQuery asyncQuery
|> connection.InsertOutputAsync<'a, 'a> |> connection.InsertOutputAsync<'a, 'a>
|> RunSynchronously |> RunSynchronously
|> EnumerableToArray |> EnumerableToArray
|> closeAndReturn connection
let Update<'a> asyncQuery = let Update<'a> asyncQuery =
let connection = connectToDatabase ()
asyncQuery asyncQuery
|> connection.UpdateOutputAsync<'a, 'a> |> connection.UpdateOutputAsync<'a, 'a>
|> RunSynchronously |> RunSynchronously
|> EnumerableToArray |> EnumerableToArray
|> closeAndReturn connection
let Delete<'a> asyncQuery = let Delete<'a> asyncQuery =
let connection = connectToDatabase ()
asyncQuery asyncQuery
|> connection.DeleteAsync |> connection.DeleteAsync
|> RunSynchronously |> RunSynchronously
|> closeAndReturn connection
let NonDbSpecificQuery (sql: string) (connection: NpgsqlConnection) =
sql
|> fun str -> System.IO.File.WriteAllText("sql.log", str); str
|> connection.Execute
|> closeAndReturn connection
let rawQuery (sql: string) = connectToDatabase () |> NonDbSpecificQuery sql
let CreateTable (tableName: string) (columnList: (string * string) list) =
let columns =
columnList
|> List.filter (fun (columnName, _) -> columnName <> "id")
|> List.map (fun (columnName, columnType) -> $""" "{columnName}" {columnType} not null""")
|> String.concat ",\n\t\t\t"
$"""
create table if not exists {tableName}
(
id serial
constraint {tableName}_pk
primary key,
{columns}
);
"""
|> fun str -> System.IO.File.WriteAllText("sql.log", str); str
|> rawQuery
|> ignore

View File

@@ -2,14 +2,13 @@
open System.Collections.Generic open System.Collections.Generic
open System.Globalization open System.Globalization
open FSharp.Data.Sql
open System open System
open System.Drawing open System.Drawing
open System.IO open System.IO
open System.Linq open System.Linq
open System.Xml; open System.Xml;
open System.Xml.XPath;
open System.Xml.Xsl open System.Xml.Xsl
open DredgePos.Types
open FSharp.Reflection open FSharp.Reflection
open Thoth.Json.Net open Thoth.Json.Net
@@ -35,8 +34,9 @@ let EnumerableToArray (enumerable: IEnumerable<'T>) = enumerable.ToArray()
let getFileExtension (file: string) = Path.GetExtension file let getFileExtension (file: string) = Path.GetExtension file
let GetFileContents (file: string) = File.ReadAllText file let GetFileContents = File.ReadAllText
let GetFileName (file: string) = Path.GetFileName file let GetFileName (file: string) = Path.GetFileName file
let FileExists = File.Exists
let length (variable: 'T[]) = variable.Length let length (variable: 'T[]) = variable.Length
let first (array: 'a[]) = array[0] let first (array: 'a[]) = array[0]
@@ -100,4 +100,14 @@ let GetImageSize image =
let loadedImage = loadImage image let loadedImage = loadImage image
loadedImage.Width, loadedImage.Height loadedImage.Width, loadedImage.Height
let CurrentTime() = DateTimeOffset.Now.ToUnixTimeSeconds() |> int let CurrentTime() = DateTimeOffset.Now.ToUnixTimeSeconds() |> int
let getConfig () =
"config.json"
|> GetFileContents
|> Decode.Auto.fromString<config>
|> (fun result ->
match result with
| Ok config -> config
| Error message -> failwith ("config.json is not valid :" + message)
)

View File

@@ -1,4 +1,5 @@
module Entity module Entity
open Dapper
open Dapper.FSharp open Dapper.FSharp
open DredgeFramework open DredgeFramework
open Pluralize.NET.Core open Pluralize.NET.Core
@@ -15,7 +16,7 @@ let Create (record: 'x)=
value record value record
excludeColumn "id" excludeColumn "id"
} }
|> db.InsertOutput |> Database.InsertOutput
|> first |> first
@@ -28,7 +29,7 @@ let inline Update (record: ^x) =
where (eq "id" id) where (eq "id" id)
excludeColumn "id" excludeColumn "id"
} }
|> db.Update |> Database.Update
let GetAll<'x> = let GetAll<'x> =
let tableName = GetDatabaseTable<'x> let tableName = GetDatabaseTable<'x>
@@ -36,7 +37,7 @@ let GetAll<'x> =
select { select {
table tableName table tableName
} }
|> db.Select<'x> |> Database.Select<'x>
let GetAllByColumn<'x> (column: string) (value: obj) = let GetAllByColumn<'x> (column: string) (value: obj) =
let tableName = GetDatabaseTable<'x> let tableName = GetDatabaseTable<'x>
@@ -44,7 +45,9 @@ let GetAllByColumn<'x> (column: string) (value: obj) =
select { select {
table tableName table tableName
where (eq column value) where (eq column value)
} |> db.Select<'x> } |> Database.Select<'x>
let GetFirstByColumn<'x> (column: string) (value: obj) = (GetAllByColumn<'x> column value) |> first
let GetAllInVenue<'x> = GetAllByColumn<'x> "venue_id" (getCurrentVenue ()) let GetAllInVenue<'x> = GetAllByColumn<'x> "venue_id" (getCurrentVenue ())
let GetById<'x> (id: int) = GetAllByColumn<'x> "id" id |> first let GetById<'x> (id: int) = GetAllByColumn<'x> "id" id |> first
@@ -67,7 +70,7 @@ let DeleteById<'x> id =
delete { delete {
table tableName table tableName
where (eq "id" id) where (eq "id" id)
} |> db.Delete |> ignore } |> Database.Delete |> ignore
entity entity

View File

@@ -13,7 +13,7 @@ type reservation = {
[<CLIMutable>] [<CLIMutable>]
type venue = { type venue = {
id: int id: int
venue_name: string name: string
} }
[<CLIMutable>] [<CLIMutable>]
@@ -38,7 +38,7 @@ type floorplan_table = {
type print_group = { type print_group = {
id: int id: int
name: string name: string
printer: int printer_id: int
venue_id: int venue_id: int
} }
@@ -47,14 +47,14 @@ type sales_category = {
id: int id: int
parent: int parent: int
name: string name: string
print_group: int print_group_id: int
venue_id: int venue_id: int
} }
[<CLIMutable>] [<CLIMutable>]
type floorplan_room = { type room = {
id: int id: int
room_name: string name: string
background_image: string background_image: string
venue_id: int venue_id: int
} }
@@ -62,18 +62,23 @@ type floorplan_room = {
[<CLIMutable>] [<CLIMutable>]
type floorplan_decoration = { type floorplan_decoration = {
id: int id: int
decoration_room: int room_id: int
decoration_pos_x: int pos_x: int
decoration_pos_y: int pos_y: int
decoration_rotation: int rotation: int
decoration_width: int width: int
decoration_height: int height: int
decoration_image: string image: string
venue_id: int venue_id: int
} }
[<CLIMutable>] [<CLIMutable>]
type clerk = {id: int; clerk_name: string; clerk_login_code: int; clerk_usergroup: int} type clerk = {
id: int
name: string
login_code: int
user_group_id: int
}
[<CLIMutable>] [<CLIMutable>]
type session = {id: int; session_id: string; clerk_json: string; clerk_id: int; expires: int} type session = {id: int; session_id: string; clerk_json: string; clerk_id: int; expires: int}
@@ -82,7 +87,7 @@ type session = {id: int; session_id: string; clerk_json: string; clerk_id: int;
type order_screen_page_group = {id: int; order: int; venue_id: int; label: string; grid_id: int} type order_screen_page_group = {id: int; order: int; venue_id: int; label: string; grid_id: int}
[<CLIMutable>] [<CLIMutable>]
type grid = {id: int; grid_name: string; grid_rows: int; grid_cols: int; grid_data: string} type grid = {id: int; name: string; rows: int; cols: int; data: string}
[<CLIMutable>] [<CLIMutable>]
type button = { type button = {
@@ -100,13 +105,30 @@ type button = {
[<CLIMutable>] [<CLIMutable>]
type item = { type item = {
id: int id: int
item_code: string code: string
item_category: int sales_category_id: int
item_name: string name: string
item_type: string item_type: string
price1: int price1: int
price2: int
price3: int
price4: int
price5: int
} }
[<CLIMutable>]
type db_config = {
db_name: string
username: string
password: string
host: string
port: int
}
[<CLIMutable>]
type config = {
database: db_config
}
[<CLIMutable>]
type migration = {
id: int
name: string
timestamp: int
}

View File

@@ -13,18 +13,31 @@
<Compile Include="Core\Language.module.fs" /> <Compile Include="Core\Language.module.fs" />
<Compile Include="Core\Theme.module.fs" /> <Compile Include="Core\Theme.module.fs" />
<Compile Include="Printer.module.fs" /> <Compile Include="Printer.module.fs" />
<Compile Include="Global\View.fs" />
<Compile Include="Global\Controller.fs" />
<Compile Include="Global\Router.fs" />
<Compile Include="Entities\Floorplan_Decorations\Model.fs" /> <Compile Include="Entities\Floorplan_Decorations\Model.fs" />
<Compile Include="Entities\Floorplan_Decorations\View.fs" />
<Compile Include="Entities\Floorplan_Decorations\Controller.fs" /> <Compile Include="Entities\Floorplan_Decorations\Controller.fs" />
<Compile Include="Entities\Floorplan_Decorations\Router.fs" /> <Compile Include="Entities\Floorplan_Decorations\Router.fs" />
<Compile Include="Entities\Buttons\Model.fs" />
<Compile Include="Authenticate\Model.fs" /> <Compile Include="Authenticate\Model.fs" />
<Compile Include="Authenticate\View.fs" />
<Compile Include="Authenticate\Controller.fs" /> <Compile Include="Authenticate\Controller.fs" />
<Compile Include="Authenticate\Router.fs" /> <Compile Include="Authenticate\Router.fs" />
<Compile Include="Ajax\Controller.fs" /> <Compile Include="Ajax\Controller.fs" />
<Compile Include="Ajax\Router.fs" /> <Compile Include="Ajax\Router.fs" />
<Compile Include="Migrations\CreateDatabaseSchema.fs" />
<Compile Include="Migrations\PopulateTestData.fs" />
<Compile Include="Installer\Model.fs" />
<Compile Include="Installer\Controller.fs" />
<Compile Include="Installer\Router.fs" />
<Compile Include="Floorplan\Model.fs" /> <Compile Include="Floorplan\Model.fs" />
<Compile Include="Floorplan\View.fs" />
<Compile Include="Floorplan\Controller.fs" /> <Compile Include="Floorplan\Controller.fs" />
<Compile Include="Floorplan\Router.fs" /> <Compile Include="Floorplan\Router.fs" />
<Compile Include="OrderScreen\Model.fs" /> <Compile Include="OrderScreen\Model.fs" />
<Compile Include="OrderScreen\View.fs" />
<Compile Include="OrderScreen\Controller.fs" /> <Compile Include="OrderScreen\Controller.fs" />
<Compile Include="OrderScreen\Router.fs" /> <Compile Include="OrderScreen\Router.fs" />
<Compile Include="Reservations\Model.fs" /> <Compile Include="Reservations\Model.fs" />
@@ -106,168 +119,15 @@
<ExcludeFromSingleFile>true</ExcludeFromSingleFile> <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content> </Content>
<Content Include="views\restaurant\alert.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\authenticate.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\backupPayentsplitter.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\button.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\buttonWithImage.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\categories\BeerPage1.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\categories\BeerPage2.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\categories\DessertsPage1.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\categories\MainsPage1.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\categories\StartersPage1.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\categories\WinePage1.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\categoryButton.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\categoryMenu.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\components\posButton.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\decoratorItem.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\decoratorRow.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\floorplan.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\keyboards.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\orderBox.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\orderBoxTable.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\orderScreen.tpl - Copy.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\orderScreen.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\orderScreen\button_image.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\orderScreen\change_cover_number_button.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\orderScreen\cover_selector.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\orderScreen\grid_button.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\orderScreen\grid_container.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\orderScreen\page.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\orderScreen\page_group.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\orderScreen\page_group_button.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\paymentSplitter.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\popupBoxItems.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\roomButton.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\virtualKeyboard.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="views\restaurant\virtualNumpad.tpl.htm">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Folder Include="wwwroot\styles" /> <Folder Include="wwwroot\styles" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapper" Version="2.0.78" />
<PackageReference Include="Dapper.Contrib" Version="2.0.78" />
<PackageReference Include="Dapper.FSharp" Version="2.4.1" /> <PackageReference Include="Dapper.FSharp" Version="2.4.1" />
<PackageReference Include="FSharp.Data" Version="4.0.1" />
<PackageReference Include="Giraffe" Version="6.0.0-alpha-2" /> <PackageReference Include="Giraffe" Version="6.0.0-alpha-2" />
<PackageReference Include="Npgsql" Version="6.0.0" /> <PackageReference Include="Npgsql" Version="6.0.0" />
<PackageReference Include="Pluralize.NET.Core" Version="1.0.0" /> <PackageReference Include="Pluralize.NET.Core" Version="1.0.0" />
<PackageReference Include="Saturn" Version="0.15.0-preview03" /> <PackageReference Include="Saturn" Version="0.15.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.0" />
<PackageReference Include="FSharp.Data.SqlClient" Version="2.1.0-beta1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0-preview.2.21154.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0-preview.2.21154.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MySql.Data" Version="8.0.23" />
<PackageReference Include="MySql.Data.EntityFrameworkCore" Version="8.0.22" />
<PackageReference Include="SQLProvider" Version="1.2.1" />
<PackageReference Include="System.Drawing.Common" Version="6.0.0-preview.5.21301.5" /> <PackageReference Include="System.Drawing.Common" Version="6.0.0-preview.5.21301.5" />
<PackageReference Include="Thoth.Json.Net" Version="5.0.0" /> <PackageReference Include="Thoth.Json.Net" Version="5.0.0" />
<PackageReference Update="FSharp.Core" Version="6.0.2-beta.21631.1" /> <PackageReference Update="FSharp.Core" Version="6.0.2-beta.21631.1" />

19
Entities/Buttons/Model.fs Normal file
View File

@@ -0,0 +1,19 @@
module DredgePos.Entities.Buttons.Model
open DredgePos.Types
open DredgeFramework
let attr = Giraffe.ViewEngine.HtmlElements.attr
let getItemActionAttributes (itemCode: string) =
let item = Entity.GetFirstByColumn<item> "code" (StringTrim itemCode)
[(attr "data-item") <| jsonEncode item]
let getGridActionAttributes (gridId: int) = [(attr "data-grid") <| jsonEncode gridId]
let getActionAttributes (action: string) (actionValue: string) =
match action with
| "item" -> getItemActionAttributes actionValue
| "grid" -> actionValue |> int |> getGridActionAttributes
| _ -> []

View File

@@ -1,27 +1,13 @@
module DredgePos.Entities.Floorplan_Decorations.Controller module DredgePos.Entities.Floorplan_Decorations.Controller
open DredgeFramework
open System
open System.IO open System.IO
let getImageHTML (imageName: string, imageUrl: string) =
let vars = map [
"image_name", imageName
"image_url", imageUrl
]
Theme.loadTemplateWithVars "decoratorItem" vars
let getImageRowHtml (imagesInRow: string[]) =
let vars = map ["decorations", String.Join("", imagesInRow)]
Theme.loadTemplateWithVars "decoratorRow" vars
let generateDecorator () = let generateDecorator () =
"wwwroot/images/decorations" "wwwroot/images/decorations"
|> Directory.GetFiles |> Directory.GetFiles
|> Array.filter Model.isImageFile |> Array.filter Model.isImageFile
|> Array.map Model.GetFileNameWithoutExtension |> Array.map Model.GetFileNameWithoutExtension
|> Array.map Model.getImageName |> Array.map Model.getImageName
|> Array.map getImageHTML |> Array.map View.decoratorItem
|> Array.chunkBySize 4 |> Array.chunkBySize 4
|> Array.map getImageRowHtml |> Array.map View.decoratorRow
|> JoinArray ""

View File

@@ -0,0 +1,24 @@
module DredgePos.Entities.Floorplan_Decorations.View
open Giraffe.ViewEngine
open DredgePos.Global.View
let decoratorItem (imageName, imageUrl) =
let image = attr "data-image"
div [_class "decoratorItem"; image imageUrl] [
a [_style $"background-image:url('/images/decorations/{imageUrl}')"] []
a [] [str imageName]
]
let decoratorRow decoratorItems = div [_class "decoratorRow"] [yield! decoratorItems]
let decorator (decorationRows: XmlNode[]) =
div [_id "decorator"] [
div [_id "decoratorHeader"] [
h2 [] [lang "choose_decoration"]
a [_class "posButton hideDecorator"] [str "×"]
]
div [_id "decoratorContent"] [
yield! decorationRows
]
]

View File

@@ -2,15 +2,18 @@
open DredgeFramework open DredgeFramework
open DredgePos open DredgePos
open DredgePos.Global.Controller
open DredgePos.Entities
open DredgePos.Types open DredgePos.Types
open Giraffe open Giraffe
open Microsoft.AspNetCore.Http open Microsoft.AspNetCore.Http
open Model open Model
open System.IO
let makeRoomButton (room: floorplan_room) = let makeRoomButton (room: room) =
let vars = map [ let vars = map [
"roomId", room.id |> string "roomId", room.id |> string
"roomName", room.room_name "roomName", room.name
] ]
Theme.loadTemplateWithVars "roomButton" vars Theme.loadTemplateWithVars "roomButton" vars
@@ -47,7 +50,7 @@ let getFloorplanData (id: int) =
tables = tableList tables = tableList
decorations = Entity.GetAllInVenue<floorplan_decoration> decorations = Entity.GetAllInVenue<floorplan_decoration>
activeTableNumbers = Model.getActiveTables (getCurrentVenue()) activeTableNumbers = Model.getActiveTables (getCurrentVenue())
rooms = Entity.GetAllInVenue<floorplan_room> rooms = Entity.GetAllInVenue<room>
reservations = reservationList reservations = reservationList
|} |}
|> ajaxSuccess |> ajaxSuccess
@@ -70,24 +73,24 @@ let deleteTable (table: floorplan_table) =
table |> ajaxSuccess |> json table |> ajaxSuccess |> json
let transferTable (origin, destination) = let transferTable (origin, destination) =
Model.transferTable origin destination transferTable origin destination
let data = map ["origin", getTable origin ; "destination", getTable destination] let data = map ["origin", getTable origin ; "destination", getTable destination]
ajaxSuccess data |> json ajaxSuccess data |> json
let AddDecoration (data: floorplan_decoration) = let AddDecoration (data: floorplan_decoration) =
let image = "wwwroot/images/decorations/" + data.decoration_image let image = "wwwroot/images/decorations/" + data.image
let width, height = image |> GetImageSize let width, height = image |> GetImageSize
let aspectRatio = decimal width / decimal height let aspectRatio = decimal width / decimal height
let decoration : floorplan_decoration = { let decoration : floorplan_decoration = {
id = 0 id = 0
decoration_height = (200m / aspectRatio) |> int height = (200m / aspectRatio) |> int
decoration_width = 200 width = 200
decoration_rotation = 0 rotation = 0
decoration_image = data.decoration_image image = data.image
decoration_pos_x = data.decoration_pos_x pos_x = data.pos_x
decoration_pos_y = data.decoration_pos_y pos_y = data.pos_y
decoration_room = data.decoration_room room_id = data.room_id
venue_id = data.venue_id venue_id = data.venue_id
} }
@@ -105,23 +108,12 @@ let DeleteDecoration (decorationToDelete: floorplan_decoration) =
|> ajaxSuccess |> ajaxSuccess
|> json |> json
let loadFloorplan (ctx: HttpContext) : HttpHandler = let loadFloorplanView (ctx: HttpContext) =
Authenticate.Model.RequireClerkAuthentication ctx Authenticate.Model.RequireClerkAuthentication ctx
let roomMenu = Entity.GetAllInVenue<room> |> Array.map View.roomButton
let currentClerk = Authenticate.Model.getCurrentClerk ctx
let styles = [|"dredgepos.floorplan.css"|] |> addDefaultStyles
let scripts = [|"./external/konva.min.js" ; "dredgepos.floorplan.js"|] |> addDefaultScripts
let metaTags = [|"viewport", "user-scalable = no, initial-scale=0.8,maximum-scale=0.8 ,shrink-to-fit=yes"|] |> addDefaultMetaTags
let roomMenu = View.index styles scripts metaTags currentClerk (Floorplan_Decorations.Controller.generateDecorator ()) roomMenu
Entity.GetAllInVenue<floorplan_room>
|> Array.map makeRoomButton
|> joinWithNewLine
let variables = map [
"title", "Floorplan"
"roomMenu", roomMenu
"decorator", Entities.Floorplan_Decorations.Controller.generateDecorator()
]
let styles = ["dredgepos.floorplan.css"]
let scripts = ["./external/konva.min.js" ; "dredgepos.floorplan.js"]
let currentClerk = recordToMap <| Authenticate.Model.getCurrentClerk ctx
let arrays = map ["clerk", currentClerk]
htmlString <| Theme.loadTemplateWithVarsArraysScriptsAndStyles "floorplan" variables arrays scripts styles

View File

@@ -39,7 +39,7 @@ let tablesInRoom (roomId: int) = //Get a list of all tables in a particular room
table "floorplan_tables" table "floorplan_tables"
where (eq "room_id" roomId) where (eq "room_id" roomId)
} }
|> db.Select<floorplan_table> |> Database.Select<floorplan_table>
let getActiveTables (venueId: int) = let getActiveTables (venueId: int) =
@@ -47,7 +47,7 @@ let getActiveTables (venueId: int) =
table "floorplan_tables" table "floorplan_tables"
where (eq "venue_id" venueId) where (eq "venue_id" venueId)
} }
|> db.Select |> Database.Select
|> Array.filter tableIsOpen |> Array.filter tableIsOpen
|> Array.map (fun table -> table.table_number) |> Array.map (fun table -> table.table_number)
@@ -87,28 +87,34 @@ let saveOrderToTable orderXML tableNumber =
File.WriteAllText(tableFile, tableXML) File.WriteAllText(tableFile, tableXML)
let getTable (tableNumber : int) = let getTableSafely (tableNumber: int) =
let query = select { let query = select {
table "floorplan_tables" table "floorplan_tables"
where (eq "table_number" tableNumber + eq "venue_id" (getCurrentVenue())) where (eq "table_number" tableNumber + eq "venue_id" (getCurrentVenue()))
} }
let result = query |> db.Select<floorplan_table> query
result |> first |> Database.Select<floorplan_table>
|> Array.tryItem 0
let getTable (tableNumber : int) =
match getTableSafely tableNumber with
| None -> failwith $"Table {tableNumber} not found in current venue"
| Some table -> table
let getTableById (id : int) = let getTableById (id : int) =
select { select {
table "floorplan_tables" table "floorplan_tables"
where (eq "id" id) where (eq "id" id)
} }
|> db.Select<floorplan_table> |> Database.Select<floorplan_table>
|> first |> first
let getRoom (roomId: int) = let getRoom (roomId: int) =
select { select {
table "floorplan_rooms" table "floorplan_rooms"
where (eq "id" roomId) where (eq "id" roomId)
} |> db.Select<floorplan_room> |> first } |> Database.Select<room> |> first
let updateTablePosition (floorplanTable: floorplan_table) = Entity.Update floorplanTable let updateTablePosition (floorplanTable: floorplan_table) = Entity.Update floorplanTable
@@ -117,7 +123,7 @@ let createEmptyReservation (reservation: reservation) =
table "floorplan_tables" table "floorplan_tables"
set {| status = 2 |} set {| status = 2 |}
where(eq "id" reservation.floorplan_table_id) where(eq "id" reservation.floorplan_table_id)
} |> db.Update |> ignore } |> Database.Update |> ignore
Entity.Create reservation Entity.Create reservation
@@ -154,7 +160,7 @@ let tableExists (tableNumber: int) =
select{ select{
table "floorplan_tables" table "floorplan_tables"
where (eq "table_number" tableNumber + eq "venue_id" (getCurrentVenue())) where (eq "table_number" tableNumber + eq "venue_id" (getCurrentVenue()))
} |> db.Select<floorplan_table> |> length } |> Database.Select<floorplan_table> |> length
match numberOfResults with match numberOfResults with
| 0 -> | 0 ->
@@ -169,14 +175,14 @@ let tableExists (tableNumber: int) =
| _ -> | _ ->
let parentTableData = getTable allTables[0] let parentTableData = getTable allTables[0]
let parentRoom = getRoom parentTableData.room_id let parentRoom = getRoom parentTableData.room_id
let parentRoomName = parentRoom.room_name let parentRoomName = parentRoom.name
language.getAndReplace "error_table_exists_merged" [parentRoomName; parentTableData.table_number.ToString()] language.getAndReplace "error_table_exists_merged" [parentRoomName; parentTableData.table_number.ToString()]
| _ -> | _ ->
let tableData = getTable tableNumber let tableData = getTable tableNumber
let room = getRoom tableData.room_id let room = getRoom tableData.room_id
language.getAndReplace "error_table_exists" [room.room_name] language.getAndReplace "error_table_exists" [room.name]
let addNewTableWithoutOutput (newTable: floorplan_table) = let addNewTableWithoutOutput (newTable: floorplan_table) =
@@ -184,7 +190,7 @@ let addNewTableWithoutOutput (newTable: floorplan_table) =
table "floorplan_tables" table "floorplan_tables"
value newTable value newTable
} }
|> db.Insert |> Database.Insert
let addNewTable (newTable: floorplan_table) = Entity.Create newTable let addNewTable (newTable: floorplan_table) = Entity.Create newTable
@@ -238,7 +244,7 @@ let mergeTables parent child = //Merge two tables together
default_covers = parentTable.default_covers + childTable.default_covers default_covers = parentTable.default_covers + childTable.default_covers
|} |}
where (eq "table_number" parent + eq "venue_id" (getCurrentVenue())) where (eq "table_number" parent + eq "venue_id" (getCurrentVenue()))
} |> db.Update |> ignore } |> Database.Update |> ignore
Entity.DeleteById<floorplan_table> newChildTable.id Entity.DeleteById<floorplan_table> newChildTable.id
|> ignore |> ignore
@@ -251,7 +257,7 @@ let updateUnmergedTables parentTable childTable =
table "floorplan_tables" table "floorplan_tables"
set parentTable set parentTable
where(eq "table_number" parentTable.table_number + eq "venue_id" (getCurrentVenue())) where(eq "table_number" parentTable.table_number + eq "venue_id" (getCurrentVenue()))
} |> db.Update |> ignore } |> Database.Update |> ignore
addNewTableWithoutOutput childTable |> ignore addNewTableWithoutOutput childTable |> ignore
true true

View File

@@ -1,16 +1,17 @@
module DredgePos.Floorplan.Router module DredgePos.Floorplan.Router
open DredgePos open DredgePos
open DredgePos.Global.Router
open DredgePos.Types open DredgePos.Types
open Saturn open Saturn
open Giraffe open Giraffe
let floorplan = (warbler (fun ctx -> DredgePos.Floorplan.Controller.loadFloorplan (snd ctx))) let floorplan = (htmlViewWithContext Controller.loadFloorplanView)
let router = router { let router = router {
pipe_through Ajax.Router.pipeline pipe_through Ajax.Router.pipeline
get "/" floorplan
get "" floorplan get "" floorplan
get "/" floorplan
post "/mergeTables" (bindJson<floorplan_table[]> Controller.mergeTables) post "/mergeTables" (bindJson<floorplan_table[]> Controller.mergeTables)
post "/transformTable" (bindJson<floorplan_table> Controller.transformTable) post "/transformTable" (bindJson<floorplan_table> Controller.transformTable)
post "/createTable" (bindJson<floorplan_table> Controller.createTable) post "/createTable" (bindJson<floorplan_table> Controller.createTable)

86
Floorplan/View.fs Normal file
View File

@@ -0,0 +1,86 @@
module DredgePos.Floorplan.View
open DredgePos.Global
open DredgePos.Global.View
open DredgePos.Entities
open DredgePos.Types
open Giraffe.ViewEngine
open DredgeFramework
let pageContainer (clerk: clerk) roomMenu =
let loggedInText = str (language.getAndReplace "logged_in_as" [clerk.name])
div [_id "pageContainer"] [
div [_id "floorplanLeftColumn"] [
div [_class "topCell"] [
a [_class "posHeader"] [loggedInText]
]
div [_class "middleCell"] []
div [_class "bottomCell"] []
]
div [_id "floorplanCenterColumn"] [
div [_class "topCell"] [
yield! roomMenu
]
div [_class "middleCell"] [
div [_id "floorplanCanvas"] []
div [_id "floorplanCanvas"] []
]
div [_class "bottomCell"] [
div [_class "editControls" ; VisibleInMode ["tableSelected"]] [
div [_class "posHeader currentTable"] [
b [_class "selectedTableNumber"] []
a [_class "reservationStatus"; VisibleInMode ["reservedTableSelected"]] []
small [_class "selectedTableCovers"] []
]
a [_class "posButton placeOrderButton"] [lang "order_table"]
a [_class "posButton reserveTableButton"; InvisibleInMode ["reservedTableSelected"; "activeTableSelected"]] [lang "reserve_table"]
a [_class "posButton unreserveTableButton"; VisibleInMode ["reservedTableSelected"]] [lang "unreserve_table"]
a [_class "posButton payTableButton"; VisibleInMode ["activeTableSelected"]] [lang "pay_table"]
a [_class "posButton viewTableButton"; VisibleInMode ["activeTableSelected"]] [lang "view_table"]
]
]
]
div [_id "floorplanRightColumn"] [
div [_class "topCell"] [
a [_class "posButton logOut"] [str "×"]
]
div [_class "middleCell"] [
a [_class "posButton editModeButton"] [lang "edit_floorplan"]
div [_class "floorplanControls useVisibility"; VisibleInMode ["edit"]] [
a [_class "posButton addTableButton"] [lang "add_table"]
a [_class "posButton addDecoration"] [lang "add_decoration"]
a [_class "posButton deleteDecoration useVisibility"; VisibleInMode ["decorationSelected"; "edit"] ] [lang "delete_decoration"]
a [_class "posButton deleteTableButton useVisibility"; VisibleInMode ["tableSelected"; "edit"]] [lang "delete_table"]
a [_class "posButton changeShapeButton useVisibility"; VisibleInMode ["tableSelected"; "edit"]] [lang "change_shape"]
]
div [_class "mergeControls useVisibility"; VisibleInMode ["tableSelected"]] [
a [_class "posButton mergeButton"; ActiveInMode "merge"] [lang "merge_table"]
a [_class "posButton unmergeButton"; VisibleInMode ["tableSelected"]] [lang "unmerge_table"]
a [_class "posButton transferTableButton" ; ActiveInMode "transfer" ; VisibleInMode ["activeTableSelected"]] [lang "transfer_table"]
]
]
div [_class "bottomCell"] []
]
]
let roomButton (room: room) = a [_class "posButton roomButton"; Value (string room.id)] [str room.name ]
let index styles scripts tags clerk decoratorRows roomMenu =
[|
pageContainer clerk roomMenu
decoratorRows |> Floorplan_Decorations.View.decorator
|]
|> HtmlPage "Floorplan" (GetScripts scripts) (GetStyles styles) (GetMetaTags tags)

7
Global/Controller.fs Normal file
View File

@@ -0,0 +1,7 @@
module DredgePos.Global.Controller
open DredgeFramework
let addDefaultScripts scripts = scripts |> Array.append [|"./external/jquery.js" ; "dredgepos.core.js"; "keyboards.js";|]
let addDefaultStyles styles = styles |> Array.append [|"dark.theme.css";|]
let addDefaultMetaTags (tags: (string*string)[]) = tags |> Array.append [|"apple-mobile-web-app-capable", "yes"|]

18
Global/Router.fs Normal file
View File

@@ -0,0 +1,18 @@
module DredgePos.Global.Router
open Saturn
open Giraffe
let htmlViewWithContext func =
(fun ctx ->
func (snd ctx)
|> htmlView
)
|> warbler
let htmlViewWithContextAndId (id: int) func =
(fun ctx ->
func (snd ctx) id
|> htmlView
)
|> warbler

134
Global/View.fs Normal file
View File

@@ -0,0 +1,134 @@
module DredgePos.Global.View
open DredgeFramework
open DredgePos.Types
open Giraffe.ViewEngine
let Value = attr "data-value"
let _table (value: floorplan_table) = value |> jsonEncode |> (attr "data-table")
let VisibleInMode (value: string list) = value |> jsonEncode |> (attr "data-visible-in-mode")
let InvisibleInMode (value: string list) = value |> jsonEncode |> (attr "data-invisible-in-mode")
let ActiveInMode (value: string) = value |> (attr "data-active-in-mode")
let innerText = str
let lang key = language.get key |> str
let template = tag "template"
let scriptToHTML (scriptFile: string) =
let scriptPath = $"/scripts/{scriptFile}"
match FileExists ("wwwroot" + scriptPath) with
| true -> script [_src scriptPath] []
| false -> comment $"[Missing script: {scriptFile}]"
let GetScripts (scripts: string[]) = scripts |> Array.map scriptToHTML
let styleToHTML (stylesheet:string) =
let stylePath = $"/styles/{stylesheet}"
match FileExists ("wwwroot" + stylePath) with
| true -> link [_rel "stylesheet" ; _href stylePath]
| false -> comment $"[Missing style: {stylesheet}]"
let GetStyles (scripts: string[]) = scripts |> Array.map styleToHTML
let tagToHtml (tag, content) = meta [_name tag; _content content]
let GetMetaTags (tags: (string * string)[]) = tags |> Array.map tagToHtml
let VirtualKeyboardRow numberOfButtons =
let buttons = Array.init numberOfButtons (fun _ -> a [] [])
div [_class "virtualKeyboardRow"] [
yield! buttons
]
let VirtualKeyboard =
div [_id "virtualKeyboard"] [
div [_class "headingRow"] [
h3 [_id "virtualKeyboardHeading"] []
a [_class "posButton closeKeyboards"] [str "X"]
]
input [_type "text"; _name "virtualKeyboardInput"; _id "virtualKeyboardInput"]
div [_id "virtualKeyboardButtons"] [
VirtualKeyboardRow 13
VirtualKeyboardRow 14
VirtualKeyboardRow 13
VirtualKeyboardRow 11
VirtualKeyboardRow 1
]
span [_class "forceFocus"] []
]
let VirtualNumpadButton (text: string) =
a [_href "#"; Value (text.ToLower()); _class "posButton virtualNumpadButton"] [str text]
let VirtualNumpadRow (buttons:string[]) =
div [_class "virtualNumpadRow"] [
yield! Array.map VirtualNumpadButton buttons
]
let VirtualNumpad =
div [_id "virtualNumpad"] [
div [_class "headingRow"] [
h3 [_id "virtualNumpadHeading"] []
a [_class "posButton closeKeyboards"] [str "X"]
]
div [_id "virtualNumpadInput"] []
div [_id "virtualNumpadButtons"] [
VirtualNumpadRow [|"1"; "2"; "3"|]
VirtualNumpadRow [|"4"; "5"; "6"|]
VirtualNumpadRow [|"7"; "8"; "9"|]
VirtualNumpadRow [|"0"; "."; "Clear"|]
VirtualNumpadRow [|"Submit"|]
]
]
let alert =
div [_id "alert"] [
div [_id "alertHeading"] []
div [_id "alertMessage"] []
div [_id "alertButtons"] [
a [_class "posButton"; _id "alertOk"] [lang "alert_ok"]
a [_class "posButton"; _id "alertYes"] [lang "alert_yes"]
a [_class "posButton"; _id "alertNo"] [lang "alert_no"]
]
]
let keyboards = [|
VirtualKeyboard
VirtualNumpad
alert
|]
let posButton (extraClasses: string) attrs content =
let allAttrs = [_class $"posButton {extraClasses}"] |> List.append attrs
a allAttrs content
let PosButton classes (attrs: Map<string, 'x>) text =
let attrArray =
attrs
|> Map.map (fun key value ->
(attr key) (string value)
)
|> Map.values
|> Array.ofSeq
posButton classes [
yield! attrArray
] [str text]
let HtmlPage pageTitle scripts styles tags content =
html [] [
head [] [
title [] [innerText pageTitle]
link [_rel "manifest" ; _href "/manifest.webmanifest"]
yield! styles
yield! scripts
yield! tags
]
body [] [
yield! content
yield! keyboards
]
]
let HTMLPageWithScripts pageTitle scripts content = HtmlPage pageTitle scripts [||] content
let HTMLPageWithStyles pageTitle styles content = HtmlPage pageTitle [||] styles content
let HTMLPageWithNoScriptsOrStyles pageTitle content = HtmlPage pageTitle [||] [||] content

32
Installer/Controller.fs Normal file
View File

@@ -0,0 +1,32 @@
module DredgePos.Installer.Controller
open System.Reflection
open DredgePos.Types
open FSharp.Reflection
let RunMigration (fsModule: System.Type) =
fsModule
.GetMethod("run")
.Invoke(null, [||])
|> ignore
Entity.Create {name=fsModule.FullName; timestamp=DredgeFramework.CurrentTime(); id=0} |> ignore
fsModule.FullName + " ran Successfully"
let RunAllMigrations () =
let completedMigrations =
try
Entity.GetAll<migration>
with
| _ -> [||]
|> Array.map (fun migration -> migration.name)
Assembly
.GetExecutingAssembly()
.GetTypes()
|> Array.filter FSharpType.IsModule
|> Array.filter (fun fsModule -> fsModule.Namespace = "DredgePos.Migrations")
|> Array.filter (fun fsModule -> not (completedMigrations |> Array.contains fsModule.FullName))
|> Array.sortBy (fun fsModule -> fsModule.Name)
|> Array.map RunMigration
|> (fun arr -> if arr.Length > 0 then arr else [|"No Migrations Were Run"|])
|> String.concat "<br/><hr/>"

2
Installer/Model.fs Normal file
View File

@@ -0,0 +1,2 @@
module DredgePos.Installer.Model

10
Installer/Router.fs Normal file
View File

@@ -0,0 +1,10 @@
module DredgePos.Installer.Router
open DredgePos
open Saturn
open Giraffe
let router = router {
pipe_through Ajax.Router.pipeline
get "/" (warbler (fun _ -> htmlString (Controller.RunAllMigrations ())))
}

View File

@@ -0,0 +1,131 @@
module DredgePos.Migrations.CreateDatabaseSchema
open DredgePos.Types
open Database
open Dapper.FSharp
open Dapper.FSharp.PostgreSQL
let CreateDatabase (db: db_config) connectionString =
let connection = connect connectionString
connection
|> NonDbSpecificQuery $"""
CREATE DATABASE {db.db_name};
"""
let addTables () =
CreateTable "sessions" [
"session_id", "varchar(200)"
"clerk_json", "text"
"clerk_id", "int"
"expires", "int"
]
CreateTable "grids" [
"name", "varchar(60)"
"rows", "int"
"cols", "int"
"data", "text"
]
CreateTable "reservations" [
"name", "varchar(100)"
"time", "int"
"covers", "int"
"floorplan_table_id", "int"
"created_at", "int"
]
CreateTable "venues" [
"name", "varchar(60)"
]
CreateTable "floorplan_tables" [
"table_number", "int"
"room_id", "int"
"venue_id", "int"
"pos_x", "int"
"pos_y", "int"
"shape", "varchar(12)"
"width", "int"
"height", "int"
"default_covers", "int"
"rotation", "int"
"merged_children", "text"
"previous_state", "text"
"status", "int"
]
CreateTable "print_groups" [
"name", "varchar(20)"
"printer_id", "int"
"venue_id", "int"
]
CreateTable "sales_categories" [
"parent", "int"
"name", "varchar(20)"
"print_group_id", "int"
"venue_id", "int"
]
CreateTable "rooms" [
"name", "varchar(20)"
"background_image", "varchar(100)"
"venue_id", "int"
]
CreateTable "floorplan_decorations" [
"room_id", "int"
"pos_x", "int"
"pos_y", "int"
"rotation", "int"
"width", "int"
"height", "int"
"image", "varchar(100)"
"venue_id", "int"
]
CreateTable "clerks" [
"name", "varchar(20)"
"login_code", "int"
"user_group_id", "int"
]
CreateTable "order_screen_page_groups" [
"order", "int"
"venue_id", "int"
"label", "varchar(40)"
"grid_id", "int"
]
CreateTable "buttons" [
"text", "varchar(60)"
"primary_action", "varchar(15)"
"primary_action_value", "varchar(20)"
"secondary_action", "varchar(15)"
"secondary_action_value", "varchar(20)"
"image", "varchar(60)"
"extra_classes", "text"
"extra_styles", "text"
]
CreateTable "items" [
"code", "varchar(40)"
"sales_category_id", "int"
"name", "varchar(60)"
"item_type", "varchar(12)"
"price1", "int"
]
CreateTable "migrations" [
"name", "varchar(100)"
"timestamp", "int"
]
let run () =
let db = getDatabaseSettings ()
$"Server={db.host};Port={db.port};User Id={db.username};Password={db.password};Include Error Detail=true"
|> CreateDatabase db
|> ignore
|> addTables

View File

@@ -0,0 +1,380 @@
module DredgePos.Migrations.PopulateTestData
open DredgeFramework
open DredgePos.Types
open System.IO
let spaceButton () = (Entity.GetFirstByColumn<button> "primary_action" "spacer").id
let CreatePageFromDirectory index (dir: string) =
let dirName = DirectoryInfo(dir).Name
let printGroup =
match dirName.ToLower() with
| "beer" | "wine" -> (Entity.GetFirstByColumn<print_group> "name" "Beverage").id
| _ -> (Entity.GetFirstByColumn<print_group> "name" "Food").id
let parentName =
match dirName.ToLower() with
| "beer" | "wine" -> "Beverage"
| _ -> "Food"
let parentCategory = Entity.GetFirstByColumn<sales_category> "name" parentName
if dirName.ToLower() <> "dips" && dirName.ToLower() <> "Steak Temperatures" then
let NewGrid = Entity.Create {
id=0
name=dirName
rows=8
cols=6
data=""
}
Entity.Create {
id=0
order=index
venue_id=1
label=dirName
grid_id=NewGrid.id
} |> ignore
else ()
Entity.Create {
id=0
parent=parentCategory.id
name=dirName
print_group_id=printGroup
venue_id=1
} |> ignore
dir
let CreateDefaultPrintGroups (path: string) =
Entity.Create {
id=0
name="Food"
printer_id=1
venue_id=1
} |> ignore
Entity.Create {
id=0
name="Beverage"
printer_id=1
venue_id=1
} |> ignore
path
let CreateDefaultVenue (path: string) =
let venue: venue = {
id=0
name="Megalomania"
}
Entity.Create venue
|>ignore
path
let CreateDefaultClerk (path: string) =
let venue: clerk = {
id=0
name="Josh"
login_code=1408
user_group_id=1
}
Entity.Create venue
|>ignore
path
let CreateDefaultSalesCategories (path: string) =
Entity.Create {
id=0
parent=0
name="Food"
print_group_id=(Entity.GetFirstByColumn<print_group> "name" "Food").id
venue_id=1
} |> ignore
Entity.Create {
id=0
parent=0
name="Beverage"
print_group_id=(Entity.GetFirstByColumn<print_group> "name" "Beverage").id
venue_id=1
} |> ignore
path
let CreateDefaultButtons (path: string) =
Entity.Create {
id = 0
text = ""
primary_action = "spacer"
secondary_action = ""
primary_action_value = ""
secondary_action_value = ""
image = ""
extra_classes = "invisible"
extra_styles = ""
}
|> ignore
path
let CreateDefaultItems (path: string) =
Entity.Create {
id = 0
name = "Custom Item"
code = "OPEN000"
sales_category_id = (Entity.GetFirstByColumn<sales_category> "name" "Food").id
item_type = "item"
price1 = 0
}
|> ignore
path
let CreateRooms () =
"wwwroot/images/rooms"
|> Directory.GetFiles
|> Array.filter (fun file -> Path.GetExtension file = ".png" || Path.GetExtension file = ".jpg")
|> Array.iter (fun image ->
let roomName = Path.GetFileNameWithoutExtension image
Entity.Create {
id=0
name=roomName
background_image= Path.GetFileName image
venue_id=1
} |> ignore
)
let populateEntreeGrid () =
let SalesCategory = Entity.GetFirstByColumn<sales_category> "name" "Entrees"
let DipSalesCategory = Entity.GetFirstByColumn<sales_category> "name" "Dips"
let Entrees = Entity.GetAllByColumn<item> "sales_category_id" SalesCategory.id
let Dips = Entity.GetAllByColumn<item> "sales_category_id" DipSalesCategory.id
let space = spaceButton()
let GridData =
[|
space; space; space; space; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
|]
|> Array.mapi (fun index current ->
let isFirstColumn = (index % 6) = 0
if not isFirstColumn then current else
let entree = Entrees |> Array.tryItem (index/6)
match entree with
| None -> space
| Some x -> x.id
)
|> Array.mapi (fun index current ->
let isSecondRow = index > 6 && index < 12
if not isSecondRow then current else
let entree = Dips |> Array.tryItem (index-7)
match entree with
| None -> space
| Some x -> x.id
)
let grid =
Entity.GetFirstByColumn<order_screen_page_group> "label" "Entrees"
|> Entity.GetRelated<grid, order_screen_page_group>
let newGrid = {grid with data=(jsonEncode {|page1=GridData|})}
Entity.Update newGrid |> ignore
()
let populateMainGrid (category: string) () =
let SalesCategory = Entity.GetFirstByColumn<sales_category> "name" category
let Mains = Entity.GetAllByColumn<item> "sales_category_id" SalesCategory.id
let space = spaceButton()
let getId index =
match Mains |> Array.tryItem index with
| None -> space
| Some x -> x.id
let GridData =
[|
getId 0; space; getId 1; space; getId 2; space;
space; space; space; space; space; space;
getId 3; space; getId 4; space; getId 5; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
|]
let grid =
Entity.GetFirstByColumn<order_screen_page_group> "label" category
|> Entity.GetRelated<grid, order_screen_page_group>
let newGrid = {grid with data=(jsonEncode {|page1=GridData|})}
Entity.Update newGrid |> ignore
let populateDessertGrid () =
let space = spaceButton()
let SalesCategory = Entity.GetFirstByColumn<sales_category> "name" "Dessert"
let Desserts = Entity.GetAllByColumn<item> "sales_category_id" SalesCategory.id
let getId index =
match Desserts |> Array.tryItem index with
| None -> space
| Some x -> x.id
let GridData =
[|
getId 0; space; getId 1; space; space ; space;
space; space; space; space; space; space;
space; getId 2; space; getId 4; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
space; space; space; space; space; space;
|]
let grid =
Entity.GetFirstByColumn<order_screen_page_group> "label" "Dessert"
|> Entity.GetRelated<grid, order_screen_page_group>
let newGrid = {grid with data=(jsonEncode {|page1=GridData|})}
Entity.Update newGrid |> ignore
let populateBeerGrid () =
let space = spaceButton()
let SalesCategory = Entity.GetFirstByColumn<sales_category> "name" "Beer"
let Beers = Entity.GetAllByColumn<item> "sales_category_id" SalesCategory.id
let grid =
Entity.GetFirstByColumn<order_screen_page_group> "label" "Beer"
|> Entity.GetRelated<grid, order_screen_page_group>
let mutable buttonMap = Map.empty<string, int[]>
Beers
|> Array.chunkBySize 24
|> Array.map (fun beerPage ->
let getId index =
match beerPage |> Array.tryItem index with
| None -> space
| Some x -> x.id
[|
getId 0; getId 1; getId 2; getId 3; getId 4 ; getId 5;
space; space; space; space; space; space;
getId 6; getId 7; getId 8; getId 9; getId 10 ; getId 11;
space; space; space; space; space; space;
getId 12; getId 13; getId 14; getId 15; getId 16 ; getId 17;
space; space; space; space; space; space;
getId 18; getId 19; getId 20; getId 21; getId 22 ; getId 23;
space; space; space; space; space; space;
|]
)
|> Array.iteri (fun index buttonIds ->
buttonMap <- buttonMap |> Map.add $"page{index+1}" buttonIds
)
let GridData = buttonMap |> jsonEncode
let newGrid = {grid with data=GridData}
Entity.Update newGrid |> ignore
let populateSteakTemperaturesGrid () =
let space = spaceButton()
let SalesCategory = Entity.GetFirstByColumn<sales_category> "name" "Steak Temperatures"
let Temps = Entity.GetAllByColumn<item> "sales_category_id" SalesCategory.id
let grid =
Entity.GetFirstByColumn<order_screen_page_group> "label" "Steak Temperatures"
|> Entity.GetRelated<grid, order_screen_page_group>
let getId index =
match Temps |> Array.tryItem index with
| None -> space
| Some x -> x.id
let GridData =
[|
getId 0; space; getId 1; space; getId 2; space;
space; space; space; space; space; space;
getId 3; space; getId 4; space; getId 5; space;
space; space; space; space; space; space;
|]
let newGrid = {grid with data=(jsonEncode {|page1=GridData|}); rows=4; cols=6}
Entity.Update newGrid |> ignore
let steakButtons = Entity.GetAllByColumn<button> "text" "Venison Wellington"
steakButtons |> Array.iter (fun button ->
Entity.Update {button with secondary_action="grid"; secondary_action_value=newGrid.id.ToString()} |> ignore
)
let PopulateGrids () =
populateEntreeGrid ()
|> populateMainGrid "Mains"
|> populateMainGrid "Wine"
|> populateDessertGrid
|> populateBeerGrid
|> populateSteakTemperaturesGrid
let CreateItemFromFileName (index: int) (dirName: string) (file: string) =
let extension = Path.GetExtension file
let fileName = Path.GetFileNameWithoutExtension file
let itemType =
match dirName.ToLower() with
| "dips" -> "instruction"
| "steak temperatures" -> "instruction"
| _ -> "item"
let categories = (Entity.GetAllByColumn<sales_category> "name" dirName)
let categoryID =
if categories.Length > 0 then categories[0].id
else 1
let newItem = Entity.Create {
id = 0
code = $"{dirName}0{index+1}" |> StringReplace " " ""
sales_category_id=categoryID
name=fileName
item_type=itemType
price1=10
}
let classes =
match dirName.ToLower() with
| "beer" | "dessert" -> "doubleHeight"
| "mains" | "wine" | "steak temperatures" -> "doubleHeight doubleWidth"
| "entrees" -> "doubleWidth"
| _ -> "normal"
Entity.Create {
id=0
text=fileName
primary_action="item"
primary_action_value=newItem.code
secondary_action="None"
secondary_action_value=""
image= $"{dirName}/{fileName}{extension}"
extra_classes=classes
extra_styles=""
} |> ignore
let CreateItemsAndButtons (dir: string) =
let dirName = DirectoryInfo(dir).Name
dir
|> Directory.GetFiles
|> Array.filter (fun file -> Path.GetExtension file = ".png" || Path.GetExtension file = ".jpg")
|> Array.iteri (fun index -> CreateItemFromFileName index dirName)
let run () =
"wwwroot/images/items"
|> CreateDefaultVenue
|> CreateDefaultClerk
|> CreateDefaultPrintGroups
|> CreateDefaultSalesCategories
|> CreateDefaultItems
|> CreateDefaultButtons
|> Directory.GetDirectories
|> Array.mapi CreatePageFromDirectory
|> Array.iter CreateItemsAndButtons
|> CreateRooms
|> PopulateGrids

View File

@@ -3,87 +3,88 @@
open DredgePos open DredgePos
open DredgeFramework open DredgeFramework
open DredgePos.Types open DredgePos.Types
open DredgePos.Global.Controller
open Saturn.CSRF
open Thoth.Json.Net
open Giraffe open Giraffe
open Microsoft.AspNetCore.Http open Microsoft.AspNetCore.Http
open FSharp.Collections
let getOrderScreenData (tableNumber: int) = let getOrderScreenData (tableNumber: int) =
{| {|
order_screen_pages = Entity.GetAllInVenue<order_screen_page_group> order_screen_pages = Entity.GetAllInVenue<order_screen_page_group>
sales_categories = Entity.GetAllInVenue<sales_category> sales_categories = Entity.GetAllInVenue<sales_category>
print_groups = Entity.GetAllInVenue<print_group> print_groups = Entity.GetAllInVenue<print_group>
custom_item = Entity.GetAllByColumn<item> "item_code" "OPEN000" |> first custom_item = Entity.GetFirstByColumn<item> "code" "OPEN000"
table = Floorplan.Model.getTable tableNumber table = Floorplan.Model.getTable tableNumber
|} |}
|> ajaxSuccess |> ajaxSuccess
|> json |> json
let renderGrid (grid: grid) =
let gridData = grid.data |> Decode.Auto.fromString<Map<string, int[]>>
match gridData with
| Error message -> failwith message
| Ok data ->
data
|> Map.toArray
|> Array.map snd
|> Array.map(
fun buttonIds ->
buttonIds
|> Array.map Entity.GetById<button>
|> Array.map View.itemButton
|> View.gridPage grid
)
let loadGrid (gridId: int) = let loadGrid (gridId: int) =
let grid = Entity.GetById<grid> gridId let grid = Entity.GetById<grid> gridId
let gridHtml = Model.loadGrid gridId let gridNodes = (renderGrid grid) |> List.ofArray
let gridHtml = Giraffe.ViewEngine.RenderView.AsString.htmlNodes gridNodes
if gridHtml = "Error" then ajaxFail gridHtml if gridHtml = "Error" then ajaxFail gridHtml
else ajaxSuccess {|grid=grid;gridHtml=gridHtml|} else ajaxSuccess {|grid=grid;gridHtml=gridHtml|}
|> json |> json
let loadOrderScreen (ctx: HttpContext) (tableNumber: int) : HttpHandler = let loadOrderScreenView (ctx: HttpContext) (tableNumber: int) =
Authenticate.Model.RequireClerkAuthentication ctx Authenticate.Model.RequireClerkAuthentication ctx
let tableOption = DredgePos.Floorplan.Model.getTableSafely tableNumber
let attr = Giraffe.ViewEngine.HtmlElements.attr
let table = Floorplan.Model.getTable tableNumber match tableOption with
| None ->
Browser.redirect "/" ctx
View.posButtonTemplate
| Some table ->
let currentClerk = Authenticate.Model.getCurrentClerk ctx
let styles = [|"dredgepos.orderScreen.css"|] |> addDefaultStyles
let scripts = [|"dredgepos.tables.js";"./external/currency.min.js";"dredgepos.orderScreen.js"; |] |> addDefaultScripts
let metaTags = [|"viewport", "user-scalable = no, initial-scale=0.8,maximum-scale=0.8 ,shrink-to-fit=yes"|] |> addDefaultMetaTags
let covers = if tableNumber > 0 then table.default_covers else 0 let printGroupButtons =
let coverString = language.getAndReplace "covers" [covers] Entity.GetAllInVenue<sales_category>
|> Array.map View.printGroupButton
let changeCoverNumberButton = if tableNumber > 0 then Theme.loadTemplateWithVars "orderScreen/change_cover_number_button" (map ["covers", coverString]) else "" let orderScreenPageGroupButtons =
Entity.GetAllInVenue<order_screen_page_group>
|> Array.filter (fun page_group -> page_group.id <> 0)
|> Array.sortBy (fun {order=order} -> order)
|> Array.map View.pageGroupButton
let orderNumber = let grids = Model.getAllPageGridsInVenue ()
if tableNumber > 0 then language.getAndReplace "active_table" [tableNumber] let pageGroupNodes =
else language.get "new_order" grids
|> Array.map(fun (grid, page_group) ->
renderGrid grid
|> View.pageGroup page_group
)
let containerAttributes = let coverSelectorButtons =
if tableNumber > 0 then Array.init (table.default_covers + 1) id
map ["data-table", jsonEncode table] |> Array.map(fun coverNumber ->
|> Theme.htmlAttributes let text = if coverNumber > 0 then language.getAndReplace "selected_cover" [coverNumber]
else "" else language.get "cover_zero"
Global.View.PosButton "coverSelectorButton" (map ["data-cover", coverNumber]) text
)
let categoryList = View.index tableNumber styles scripts metaTags currentClerk printGroupButtons orderScreenPageGroupButtons pageGroupNodes coverSelectorButtons
Entity.GetAllInVenue<order_screen_page_group>
|> Array.filter (fun page_group -> page_group.id <> 0)
|> Array.sortBy (fun {order=order} -> order)
|> Array.map (fun category ->
let categoryMap = recordToMap category
let categoryArray = map ["page", categoryMap]
Theme.loadTemplateWithArrays "orderScreen/page_group_button" categoryArray
)
|> joinWithNewLine
let grids =
Model.getAllPageGrids ()
|> Array.map Model.getPagesHTML
|> joinWithNewLine
let coverSelectorButtons =
Array.init (covers+1) id
|> Array.map(fun coverNumber ->
let text = if coverNumber > 0 then language.getAndReplace "selected_cover" [coverNumber]
else language.get "cover_zero"
Theme.PosButton text "coverSelectorButton" $"""data-cover="{coverNumber}" """)
|> String.concat "\n"
let variables = map [
"title", "Order"
"containerAttributes", containerAttributes
"categoryList", categoryList
"pageGroups", grids
"orderNumber", orderNumber
"changeCoverNumberButton", changeCoverNumberButton
"covers", coverString
"salesCategoryOverrideButtons", Model.generateSalesCategoryOverrideButtons ()
"coverSelectorButtons", coverSelectorButtons
]
let styles = ["dredgepos.orderScreen.css"]
let scripts = ["dredgepos.tables.js";"./external/currency.min.js";"dredgepos.orderScreen.js"; ]
let currentClerk = recordToMap <| Authenticate.Model.getCurrentClerk ctx
let arrays = map ["clerk", currentClerk]
Theme.loadTemplateWithVarsArraysScriptsAndStyles "orderScreen" variables arrays scripts styles
|> htmlString

View File

@@ -8,129 +8,11 @@ open Thoth.Json.Net
open Theme open Theme
let getAllPageGrids () = Entity.GetAllInVenue<order_screen_page_group> let getAllPageGridsInVenue () =
|> Array.filter(fun pageGroup -> pageGroup.grid_id <> 0) Entity.GetAllInVenue<order_screen_page_group>
|> Array.map(fun pageGroup -> (Entity.GetById<grid> pageGroup.grid_id), pageGroup) |> Array.filter(fun pageGroup -> pageGroup.grid_id <> 0)
|> Array.map(fun pageGroup -> (Entity.GetById<grid> pageGroup.grid_id), pageGroup)
let getImageButtonData (button: button) =
let itemCode =
if button.primary_action = "item" then button.primary_action_value
else button.secondary_action_value
let item = Entity.GetAllByColumn<item> "item_code" itemCode
|> first
let extraData =
map [
"data-item", jsonEncode item
] |> htmlAttributes
{|
extra_data = extraData
text = item.item_name
|}
let getGridButtonData (button: button) =
let gridId =
if button.primary_action = "grid" then button.primary_action_value
else button.secondary_action_value
|> int
let grid = Entity.GetById<grid> gridId
{|
extra_data = map ["data-grid", jsonEncode gridId] |> htmlAttributes
text = grid.grid_name
|}
let getActionData (button: button) (action: string) =
let actionValue =
if action = "primary" then button.primary_action
else button.secondary_action
match actionValue with
| "item" -> getImageButtonData button
| "grid" -> getGridButtonData button
| "spacer" -> {|extra_data=""; text=""|}
| _ -> {|extra_data=""; text=""|}
let renderButton (buttonId: int) =
let button = Entity.GetById<button> buttonId
let extra_styles =
match button.extra_styles.Length with
| 0 -> ""
| _ -> $""" style="{button.extra_styles}" """
let imageClass = if button.image.Length > 0 then "hasImage" else ""
let spacerClass = if button.primary_action = "spacer" || button.secondary_action = "spacer"
then "invisible"
else ""
let image = if button.image.Length > 0 then loadTemplateWithVars "orderScreen/button_image" (map ["image", button.image]) else ""
let extraClasses = [|imageClass; spacerClass|] |> String.concat " "
let primary_action_data = getActionData button "primary"
let secondary_action_data = getActionData button "secondary"
let action_extra_data = primary_action_data.extra_data + " " + secondary_action_data.extra_data
let button_text =
if button.text.Length > 0 then button.text
else
if primary_action_data.text.Length > 0 then primary_action_data.text
else secondary_action_data.text
let vars = map [
"extra_classes", button.extra_classes + " " + extraClasses
"extra_styles", extra_styles
"primary_action", button.primary_action
"secondary_action", button.secondary_action
"text", button_text
"image", image
"extra_data", action_extra_data
]
loadTemplateWithVars "orderScreen/grid_button" vars
let renderPage (grid: grid) (buttonHTML: string) =
let vars = map ["pageButtons", buttonHTML; "rows", string grid.grid_rows; "cols", string grid.grid_cols]
loadTemplateWithVars "orderScreen/page" vars
let renderPageGroup (pageGroup: order_screen_page_group) (pageHTML: string) =
let vars = map [
"pages", pageHTML
"page_group_id", string pageGroup.id
]
loadTemplateWithVars "orderScreen/page_group" vars
let printGroupPosButton (printGroup: print_group) = let printGroupPosButton (printGroup: print_group) =
PosButton (language.getAndReplace "print_with" [printGroup.name]) "printGroupOverrideButton toggle" $"""data-value="{printGroup.id}" """ PosButton (language.getAndReplace "print_with" [printGroup.name]) "printGroupOverrideButton toggle" $"""data-value="{printGroup.id}" """
let generateSalesCategoryOverrideButtons () =
Entity.GetAllInVenue<print_group>
|> Array.map printGroupPosButton
|> Array.append [|PosButton (language.getAndReplace "print_with" ["default"]) "printGroupOverrideButton toggle default active" """data-value="0" """|]
|> joinWithNewLine
let renderGrid (grid: grid) =
let gridData = grid.grid_data |> Decode.Auto.fromString<Map<string, int[]>>
match gridData with
| Error _ -> "Error"
| Ok pages ->
pages
|> Map.toArray
|> Array.map snd
|> Array.map(fun row -> row |> Array.map renderButton |> String.concat "\n")
|> Array.map (renderPage grid)
|> joinWithNewLine
let loadGrid gridId = renderGrid (Entity.GetById<grid> gridId)
let getPagesHTML (gridInfo: grid * order_screen_page_group) =
let grid, pageGroup = gridInfo
renderGrid grid
|> renderPageGroup pageGroup

View File

@@ -10,6 +10,5 @@ let router = router {
getf "/getOrderScreenData/%i" Controller.getOrderScreenData getf "/getOrderScreenData/%i" Controller.getOrderScreenData
getf "/getGridHtml/%i" Controller.loadGrid getf "/getGridHtml/%i" Controller.loadGrid
post "/updateCovers" (bindJson<floorplan_table> (fun table -> Entity.Update table |> Array.head |> DredgeFramework.ajaxSuccess |> json)) post "/updateCovers" (bindJson<floorplan_table> (fun table -> Entity.Update table |> Array.head |> DredgeFramework.ajaxSuccess |> json))
get "/" (warbler (fun ctx -> Controller.loadOrderScreen (snd ctx) 0)) getf "/%i" (fun number -> (warbler (fun ctx -> htmlView <| Controller.loadOrderScreenView (snd ctx) number)))
getf "/%i" (fun number -> (warbler (fun ctx -> Controller.loadOrderScreen (snd ctx) number)))
} }

159
OrderScreen/View.fs Normal file
View File

@@ -0,0 +1,159 @@
module DredgePos.OrderScreen.View
open DredgeFramework
open DredgePos.Types
open DredgePos.Global.View
open DredgePos.Entities.Buttons.Model
open Thoth.Json.Net
open Giraffe.ViewEngine
open language
let coverSelector buttons = div [_class "coverSelector"] [
yield! buttons
]
let pageContainer floorplanTable (clerk: clerk) printGroupButtons orderScreenPageGroupButtons pageGroups =
div [_id "pageContainer" ; _table floorplanTable] [
div [_id "leftColumn"] [
h1 [_class "tableHeading"] [str (getAndReplace "active_table" [floorplanTable.table_number])]
div [_class "tableInfo"] [
posButton "changeCoverNumberButton" [] [str (getAndReplace "covers" [floorplanTable.default_covers])]
posButton "" [] [str (getAndReplace "logged_in_as" [clerk.name])]
]
div [_class "orderBox"] [
table [_class "orderBoxTable"] [
thead [] [
tr [] [
th [_class "orderBoxCell qtyCell"] [str (get "qty_header")]
th [_class "orderBoxCell itemIdCell"] [str (get "id_header")]
th [_class "orderBoxCell itemCell"] [str (get "item_header")]
th [_class "orderBoxCell unitPriceCell"] [str (get "price_header")]
th [_class "orderBoxCell totalPriceCell"] [str (get "total_price_header")]
th [_class "orderBoxCell printGroupCell"] [str (get "printgroup_header")]
]
]
tbody [] []
]
]
div [_class "orderBoxInfo"] [
span [_class "voidModeWarning"; VisibleInMode ["void"]] [str (get "void_mode")]
]
div [_class "orderBoxFooter"] [
span [_class "totalPrice"] [str (getAndReplace "totalPrice" ["0.00"])]
small [_class "selectedPrice"] [str (getAndReplace "selectedPrice" ["0.00"])]
]
]
div [_id "rightColumn"] [
div [_id "topHalf"] [
div [_class "functionButtons"] [
div [_class "printGroupButtons toggleGroup"] [
input [_type "hidden"; _class "value"]
yield! printGroupButtons
]
div [_class "functionColumn"] [
posButton "accumulateButton" [ActiveInMode "accumulate"] [str (get "accumulate_function")]
posButton "showCoverSelectorButton" [] [str (get "select_covers")]
]
div [_class "functionColumn"] [
posButton "voidButton" [ActiveInMode "void"] [str (get "void")]
posButton "openItemButton" [] [str (get "custom_item_button")]
posButton "freetextButton" [] [str (get "freetext_button")]
posButton "numpadButton" [] [str (get "numpad_button")]
]
div [_class "functionColumn"] [
posButton "" [] ["pay_function" |> get |> str]
posButton "" [] ["print_function" |> get |> str]
]
]
]
div [_id "pageList"] [
yield! orderScreenPageGroupButtons
]
div [_id "pageGroupContainer"] [
yield! pageGroups
]
div [_class "pageNavigation"] [
posButton "prevButton" [] ["prev_page" |> get |> str]
posButton "nextButton" [] ["next_page" |> get |> str]
]
]
]
(* Grid Container, Cover Selector *)
let posButtonTemplate =
template [_id "posButtonTemplate"] [
posButton "" [] []
]
let gridContainer =
div [_class "gridContainer"] [
div [_class "gridContainerHeader"] [
span [] []
div [_class "posButton closeGrid"] [str "×"]
]
div [_class "gridContainerGrid"] [
div [_class "pageGroup"] []
]
div [_class "pageNavigation"] [
posButton "prevButton" [] ["prev_page" |> get |> str]
posButton "nextButton" [] ["next_page" |> get |> str]
]
]
let pageGroupButton (pageGroup: order_screen_page_group) = posButton "loadPageGroup" [(attr "data-page-group-id") (string pageGroup.id)] [str pageGroup.label]
let printGroupButton (printGroup: sales_category) = posButton "" [(attr "data-print-group-id") (string printGroup.id)] [str printGroup.name]
let itemButtonImage (button: button) =
span [
_class "buttonImg"
_style $"background-image:url(\"/images/items/{button.image}\");"
] []
let itemButton (button: button) =
let extraClasses =
if button.image.Length > 0 then button.extra_classes + " hasImage"
else button.extra_classes
let primaryAttributes = getActionAttributes button.primary_action button.primary_action_value
let secondaryAttributes = getActionAttributes button.secondary_action button.secondary_action_value
posButton extraClasses [
yield! primaryAttributes
yield! secondaryAttributes
_style button.extra_styles
(attr "data-primary-action") button.primary_action
(attr "data-secondary-action") button.secondary_action
] [
if button.image.Length > 0 then itemButtonImage button
span [_class "text "] [str button.text]
]
let _dataPageGroup = attr "data-page-group"
let _dataPageGroupId = attr "data-page-group-id"
let pageGroup (page_group: order_screen_page_group) gridNodes =
div [_class "pageGroup"; _dataPageGroupId (string page_group.id); ] [
yield! gridNodes
]
let gridPage (grid: grid) buttonNodes =
div [
_class "gridPage"
_style $"
grid-template-columns: repeat({grid.cols}, 1fr);
grid-template-rows: repeat({grid.rows}, 1fr);"
] [
yield! buttonNodes
]
let index orderNumber styles scripts tags clerk printGroupButtons orderScreenPageGroupButtons pageGroupNodes coverSelectorButtons =
[|
pageContainer (DredgePos.Floorplan.Model.getTable orderNumber) clerk printGroupButtons orderScreenPageGroupButtons pageGroupNodes
posButtonTemplate
gridContainer
coverSelector coverSelectorButtons
|]
|> HtmlPage "Order" (GetScripts scripts) (GetStyles styles) (GetMetaTags tags)

View File

@@ -14,6 +14,7 @@ module Program =
forward "/order" DredgePos.OrderScreen.Router.router forward "/order" DredgePos.OrderScreen.Router.router
forward "/login" DredgePos.Authenticate.Router.router forward "/login" DredgePos.Authenticate.Router.router
forward "/reservations" DredgePos.Reservations.Router.router forward "/reservations" DredgePos.Reservations.Router.router
forward "/install" DredgePos.Installer.Router.router
} }
let app = application { let app = application {

View File

@@ -10,11 +10,11 @@ let updateReservation (reservation: reservation) =
table "reservations" table "reservations"
set reservation set reservation
where(eq "id" reservation.id) where(eq "id" reservation.id)
} |> db.Update |> ignore } |> Database.Update |> ignore
reservation reservation
let DeleteReservation (tableId: int) = let DeleteReservation (tableId: int) =
delete { delete {
table "reservations" table "reservations"
where (eq "floorplan_table_id" tableId) where (eq "floorplan_table_id" tableId)
} |> db.Delete |> ignore } |> Database.Delete |> ignore

9
config.json Normal file
View File

@@ -0,0 +1,9 @@
{
"database": {
"db_name": "dredgepos",
"username": "postgres",
"password": "root",
"host": "localhost",
"port": 5432
}
}

View File

@@ -14,8 +14,8 @@
"license": "", "license": "",
"repository": "", "repository": "",
"scripts": { "scripts": {
"sass": "sass sass:wwwroot/styles", "sass": "sass sass:wwwroot/styles",
"typescript": "tsc", "typescript": "tsc",
"build" : "npm run sass && npm run typescript" "build": "npm run sass && npm run typescript"
} }
} }

View File

@@ -268,6 +268,9 @@
text-align: center text-align: center
width: 60% width: 60%
.itemIdCell
display: none
.qtyCell .qtyCell
width: 10% width: 10%

View File

@@ -11,7 +11,7 @@ interface floorplan{
tableLayer: Konva.Layer tableLayer: Konva.Layer
rooms: room[] rooms: room[]
tables: floorplan_table[] tables: floorplan_table[]
decorations: decoration[] decorations: floorplan_decoration[]
activeTableNumbers: number[] activeTableNumbers: number[]
selectedTableNumber: number selectedTableNumber: number
selectedDecorationId: number selectedDecorationId: number
@@ -25,7 +25,7 @@ interface floorplan{
interface floorplan_data{ interface floorplan_data{
tables: floorplan_table[] tables: floorplan_table[]
decorations: decoration[] decorations: floorplan_decoration[]
activeTableNumbers: number[] activeTableNumbers: number[]
rooms: room[] rooms: room[]
reservations:reservation[] reservations:reservation[]
@@ -122,7 +122,7 @@ const loadRoom = (roomToLoad: room) => {
button.addClass('active') button.addClass('active')
const tablesInRoom = Floorplan.tables.filter(table => table.room_id == roomToLoad.id) const tablesInRoom = Floorplan.tables.filter(table => table.room_id == roomToLoad.id)
const decorationsInRoom = Floorplan.decorations.filter(decoration => decoration.decoration_room == roomToLoad.id) const decorationsInRoom = Floorplan.decorations.filter(decoration => decoration.room_id == roomToLoad.id)
decorationsInRoom.forEach(decoration => createDecorationShape(decoration, false)) decorationsInRoom.forEach(decoration => createDecorationShape(decoration, false))
tablesInRoom.forEach(createTableShape) tablesInRoom.forEach(createTableShape)
if(!isInMode('transfer')) { if(!isInMode('transfer')) {
@@ -173,7 +173,7 @@ const createTableShape = (table: floorplan_table) => {
stroke: "black", stroke: "black",
strokeWidth: 4, strokeWidth: 4,
draggable: false, draggable: false,
listening: true listening: true,
}); });
break; break;
default: default:
@@ -469,21 +469,21 @@ const tableDblClicked = (event: Konva.KonvaEventObject<any>) => {
} }
const createDecorationShape = (decoration:decoration, select?: boolean) => { const createDecorationShape = (decoration:floorplan_decoration, select?: boolean) => {
const draggable = isInMode('edit') const draggable = isInMode('edit')
const decorationShape = new Image() const decorationShape = new Image()
decorationShape.onload = () => { decorationShape.onload = () => {
const decorationImage = new Konva.Image({ const decorationImage = new Konva.Image({
id: decoration.id.toString(), id: decoration.id.toString(),
x: decoration.decoration_pos_x * Floorplan.visualScale, x: decoration.pos_x * Floorplan.visualScale,
y: decoration.decoration_pos_y * Floorplan.visualScale, y: decoration.pos_y * Floorplan.visualScale,
image: decorationShape, image: decorationShape,
offsetX: decoration.decoration_width * 0.5 * Floorplan.visualScale, offsetX: decoration.width * 0.5 * Floorplan.visualScale,
offsetY: decoration.decoration_height * 0.5 * Floorplan.visualScale, offsetY: decoration.height * 0.5 * Floorplan.visualScale,
rotation: decoration.decoration_rotation, rotation: decoration.rotation,
width: decoration.decoration_width * Floorplan.visualScale, width: decoration.width * Floorplan.visualScale,
height: decoration.decoration_height * Floorplan.visualScale, height: decoration.height * Floorplan.visualScale,
draggable: draggable, draggable: draggable,
}); });
@@ -500,7 +500,7 @@ const createDecorationShape = (decoration:decoration, select?: boolean) => {
} }
} }
decorationShape.src = '/images/decorations/' + decoration.decoration_image decorationShape.src = '/images/decorations/' + decoration.image
} }
const setupDecorationEvents = (decorationShape: Konva.Image) => { const setupDecorationEvents = (decorationShape: Konva.Image) => {
@@ -541,22 +541,22 @@ const getDecorationDataById = (id: number) => {
const decorationTransformed = (event: Konva.KonvaEventObject<MouseEvent>|Konva.KonvaEventObject<TouchEvent|DragEvent|MouseEvent>) => { const decorationTransformed = (event: Konva.KonvaEventObject<MouseEvent>|Konva.KonvaEventObject<TouchEvent|DragEvent|MouseEvent>) => {
let decorationShape = event.currentTarget as Konva.Image let decorationShape = event.currentTarget as Konva.Image
const oldDecorationData = getDecorationDataById(Number(decorationShape.id())) const oldDecorationData = getDecorationDataById(Number(decorationShape.id()))
const newDecoration: decoration = { const newDecoration: floorplan_decoration = {
id: oldDecorationData.id, id: oldDecorationData.id,
decoration_room: oldDecorationData.decoration_room, room_id: oldDecorationData.room_id,
decoration_pos_x: Math.round(decorationShape.x() / Floorplan.visualScale), pos_x: Math.round(decorationShape.x() / Floorplan.visualScale),
decoration_pos_y: Math.round(decorationShape.y() / Floorplan.visualScale), pos_y: Math.round(decorationShape.y() / Floorplan.visualScale),
decoration_rotation: Math.round(decorationShape.rotation()), rotation: Math.round(decorationShape.rotation()),
decoration_width: Math.round((decorationShape.scaleX() * decorationShape.width()) / Floorplan.visualScale), width: Math.round((decorationShape.scaleX() * decorationShape.width()) / Floorplan.visualScale),
decoration_height: Math.round((decorationShape.scaleY() * decorationShape.height()) / Floorplan.visualScale), height: Math.round((decorationShape.scaleY() * decorationShape.height()) / Floorplan.visualScale),
decoration_image: oldDecorationData.decoration_image, image: oldDecorationData.image,
venue_id: oldDecorationData.venue_id, venue_id: oldDecorationData.venue_id,
} }
saveDecoration(newDecoration) saveDecoration(newDecoration)
} }
const saveDecoration = (decorationToUpdate: decoration) => { const saveDecoration = (decorationToUpdate: floorplan_decoration) => {
const decorations = const decorations =
Floorplan Floorplan
.decorations .decorations
@@ -576,22 +576,22 @@ const hideDecorator = () => $('#decorator').css('display', 'flex').hide()
const addDecoration = (e: Event) => { const addDecoration = (e: Event) => {
const button = $(e.currentTarget) const button = $(e.currentTarget)
const newDecoration: decoration = { const newDecoration: floorplan_decoration = {
id: 0, id: 0,
decoration_room: Floorplan.currentRoom.id, room_id: Floorplan.currentRoom.id,
decoration_pos_x: Floorplan.visualScaleBasis / 2, pos_x: Floorplan.visualScaleBasis / 2,
decoration_pos_y: Floorplan.visualScaleBasis / 2, pos_y: Floorplan.visualScaleBasis / 2,
decoration_rotation: 0, rotation: 0,
decoration_width: 200, width: 200,
decoration_height: 200, height: 200,
decoration_image: button.data('image'), image: button.data('image'),
venue_id: Floorplan.currentRoom.venue_id venue_id: Floorplan.currentRoom.venue_id
} }
ajax('/floorplan/addDecoration', newDecoration, 'post', decorationAdded, null, null) ajax('/floorplan/addDecoration', newDecoration, 'post', decorationAdded, null, null)
} }
const decorationAdded = (decoration: decoration) => { const decorationAdded = (decoration: floorplan_decoration) => {
Floorplan.decorations.push(decoration) Floorplan.decorations.push(decoration)
createDecorationShape(decoration, true) createDecorationShape(decoration, true)
@@ -604,7 +604,7 @@ const deleteDecoration = () => ajax(
getDecorationDataById(Floorplan.selectedDecorationId), getDecorationDataById(Floorplan.selectedDecorationId),
'post', decorationDeleted, null, null) 'post', decorationDeleted, null, null)
const decorationDeleted = (deletedDecoration:decoration) => { const decorationDeleted = (deletedDecoration:floorplan_decoration) => {
Floorplan.decorations = Floorplan.decorations.filter(decoration => decoration.id != deletedDecoration.id) Floorplan.decorations = Floorplan.decorations.filter(decoration => decoration.id != deletedDecoration.id)
const decorationShape = Floorplan.stage.findOne(`#${deletedDecoration.id}`) const decorationShape = Floorplan.stage.findOne(`#${deletedDecoration.id}`)
decorationShape.destroy() decorationShape.destroy()
@@ -615,9 +615,11 @@ const setRoomBackground = (roomToLoad: room) => {
const width = Floorplan.floorplanDiv.width() const width = Floorplan.floorplanDiv.width()
const height = Floorplan.floorplanDiv.height() const height = Floorplan.floorplanDiv.height()
if(roomToLoad.background_image) { if(roomToLoad.background_image != "") {
Floorplan.floorplanDiv.css("background-image", `url(/images/rooms/${roomToLoad?.background_image})`) Floorplan.floorplanDiv.css("background-image", `url('/images/rooms/${roomToLoad.background_image}')`)
Floorplan.floorplanDiv.css("background-size", `${width}px ${height}px`) Floorplan.floorplanDiv.css("background-size", `${width}px ${height}px`)
} else {
Floorplan.floorplanDiv.css("background-image", "none")
} }
} }

View File

@@ -43,7 +43,6 @@ const loadPageGroup = (e: Event) => {
button.addClass('active') button.addClass('active')
let pageGroupId = button.data('page-group-id') let pageGroupId = button.data('page-group-id')
container.find('.pageGroup').hide() container.find('.pageGroup').hide()
let activeGrid = $(`.pageGroup[data-page-group-id=${pageGroupId}]`) let activeGrid = $(`.pageGroup[data-page-group-id=${pageGroupId}]`)
@@ -59,7 +58,6 @@ const loadPageGroup = (e: Event) => {
const setupOrderScreen = (data: OrderScreenData) => { const setupOrderScreen = (data: OrderScreenData) => {
$('.coverSelector, .gridContainer').hide()
OrderScreen.order_screen_pages = data.order_screen_pages OrderScreen.order_screen_pages = data.order_screen_pages
OrderScreen.sales_categories = data.sales_categories OrderScreen.sales_categories = data.sales_categories
@@ -123,7 +121,7 @@ const addItemToOrderBox = (orderItem:orderItem) => {
const existingRow = orderBox const existingRow = orderBox
.find('tr') .find('tr')
.filterByData('item', orderItem.item) .filterByData('item', orderItem.item)
.filterByData('print_group', orderItem.print_group) .filterByData('print_group', orderItem.print_group_id)
.filterByData('cover', orderItem.cover) .filterByData('cover', orderItem.cover)
.last() .last()
@@ -186,13 +184,13 @@ const addInstructionToOrderBox = (instruction: orderItem) => {
const addNewItem = (item: item, qty = 1) => { const addNewItem = (item: item, qty = 1) => {
const salesCategory = OrderScreen.sales_categories.where('id', item.item_category) const salesCategory = OrderScreen.sales_categories.where('id', item.sales_category_id)
const printGroup = OrderScreen.print_group_override ?? OrderScreen.print_groups.where('id', salesCategory.print_group) const printGroup = OrderScreen.print_group_override ?? OrderScreen.print_groups.where('id', salesCategory.print_group_id)
const orderItem : orderItem = { const orderItem : orderItem = {
id: OrderScreen.order_item_id_generator.next().value, id: OrderScreen.order_item_id_generator.next().value,
item: item, item: item,
qty: qty, qty: qty,
print_group: printGroup, print_group_id: printGroup,
cover: OrderScreen.selected_cover, cover: OrderScreen.selected_cover,
} }
@@ -223,11 +221,11 @@ const getLastInstructionRow = (row: JQuery) => {
return $(finalRow) return $(finalRow)
} }
const getParentRow = (row: JQuery) => { const getParentRow = (row: JQuery) =>
return row.hasClass('instructionRow') row.hasClass('instructionRow')
? row.prevAll('.itemRow').first() ? row.prevAll('.itemRow').first()
: row : row
}
const incrementRowQty = (row: JQuery, qty: number) => { const incrementRowQty = (row: JQuery, qty: number) => {
const existingQty = Number(row.getColumnValue(lang('qty_header'))) const existingQty = Number(row.getColumnValue(lang('qty_header')))
@@ -258,17 +256,17 @@ const renderOrderBox = () => {
const createOrderRow = (orderItem: orderItem) => { const createOrderRow = (orderItem: orderItem) => {
const row = $('.orderBoxTable').EmptyRow() const row = $('.orderBoxTable').EmptyRow()
const price = money(orderItem.item.price1) const price = money(orderItem.item.price1)
const itemCellText = $('<span/>').text(orderItem.item.item_name) const itemCellText = $('<span/>').text(orderItem.item.name)
row row
.addClass(`${orderItem.item.item_type}Row`) .addClass(`${orderItem.item.item_type}Row`)
.setColumnValue(lang('qty_header'), orderItem.qty) .setColumnValue(lang('qty_header'), orderItem.qty)
.setColumnValue(lang('price_header'), price) .setColumnValue(lang('price_header'), price)
.setColumnValue(lang('id_header'), orderItem.item.id) .setColumnValue(lang('id_header'), orderItem.item.id)
.setColumnValue(lang('total_price_header'), price.multiply(orderItem.qty)) .setColumnValue(lang('total_price_header'), price.multiply(orderItem.qty))
.setColumnValue(lang('printgroup_header'), orderItem.print_group?.name) .setColumnValue(lang('printgroup_header'), orderItem.print_group_id?.name)
.data('order-item-id', orderItem.id) .data('order-item-id', orderItem.id)
.data('order-item-id', orderItem.id) .data('order-item-id', orderItem.id)
.data('print_group', orderItem.print_group) .data('print_group', orderItem.print_group_id)
.data('cover', orderItem.cover) .data('cover', orderItem.cover)
.data('item', orderItem.item) .data('item', orderItem.item)
.find('td.itemCell') .find('td.itemCell')
@@ -306,7 +304,6 @@ const gridButtonClicked = (e: JQuery.TriggeredEvent) => {
ajax(`/order/getGridHtml/${grid}`, null, null,gridHtmlGenerated, null, null) ajax(`/order/getGridHtml/${grid}`, null, null,gridHtmlGenerated, null, null)
} }
const hideGrids = () => $('.gridContainer').hide() const hideGrids = () => $('.gridContainer').hide()
@@ -319,17 +316,17 @@ const gridHtmlGenerated = (gridData: {gridHtml:string, grid: grid}) => {
gridContainer gridContainer
.show() .show()
.width(gridCellWidth * grid.grid_cols) .width(gridCellWidth * grid.cols)
.children('.gridContainerHeader') .children('.gridContainerHeader')
.children('span') .children('span')
.text(grid.grid_name) .text(grid.name)
.parent() .parent()
.parent() .parent()
.find('.pageGroup') .find('.pageGroup')
.html(gridHtml) .html(gridHtml)
.show() .show()
.parent() .parent()
.height(gridCellHeight * grid.grid_rows) .height(gridCellHeight * grid.rows)
.closest('.gridContainer') .closest('.gridContainer')
.find('.pageNavigation') .find('.pageNavigation')
.toggle(gridContainer.find('.gridPage').length > 1) .toggle(gridContainer.find('.gridPage').length > 1)
@@ -426,6 +423,7 @@ const getTotalOfRows = (rows: JQuery) => {
const getQty = (row: JQuery) => Number(row.getColumnValue(lang('qty_header'))) const getQty = (row: JQuery) => Number(row.getColumnValue(lang('qty_header')))
const getUnitPrice = (row: JQuery) => moneyFromString(row.getColumnValue(lang('price_header'))) const getUnitPrice = (row: JQuery) => moneyFromString(row.getColumnValue(lang('price_header')))
const calculateRowTotal = (row: JQuery) => { const calculateRowTotal = (row: JQuery) => {
let price = getUnitPrice(row) let price = getUnitPrice(row)
let qty = getQty(row) let qty = getQty(row)
@@ -495,7 +493,7 @@ const freetextSubmitted = (text: string) => {
const item = Object.assign({}, OrderScreen.custom_item) const item = Object.assign({}, OrderScreen.custom_item)
item.item_type = 'instruction' item.item_type = 'instruction'
item.item_name = text item.name = text
addNewItem(item) addNewItem(item)
@@ -509,7 +507,7 @@ const customItemTextSubmitted = (text: string) => {
const item = Object.assign({}, OrderScreen.custom_item) const item = Object.assign({}, OrderScreen.custom_item)
item.item_type = 'item' item.item_type = 'item'
item.item_name = text item.name = text
item.price1 = price.intValue item.price1 = price.intValue
addNewItem(item) addNewItem(item)
@@ -600,5 +598,7 @@ const generateCoverSelector = () => {
$(() => { $(() => {
OrderScreen.table = $('#pageContainer').data('table') || null OrderScreen.table = $('#pageContainer').data('table') || null
ajax('/order/getOrderScreenData/1', null, 'get', setupOrderScreen, null, null) $('.coverSelector, .gridContainer').hide()
if(OrderScreen.table)
ajax(`/order/getOrderScreenData/${OrderScreen.table.table_number}`, null, 'get', setupOrderScreen, null, null)
}) })

View File

@@ -228,7 +228,6 @@ let showVirtualNumpad = (heading: string, maxlength = 4, isPassword: boolean, al
index = index + 1 index = index + 1
let currentRow : string[] = layoutToLoad[`row${index}${modifier}`] let currentRow : string[] = layoutToLoad[`row${index}${modifier}`]
$(row).children('a').each((keyIndex, button) => { $(row).children('a').each((keyIndex, button) => {
let key = $(button); let key = $(button);
let keyValue: string = currentRow[keyIndex]; let keyValue: string = currentRow[keyIndex];

View File

@@ -10,7 +10,7 @@ interface order {
interface orderItem { interface orderItem {
id: number id: number
qty: number qty: number
print_group: print_group print_group_id: print_group
item: item item: item
cover: number cover: number
} }
@@ -18,7 +18,7 @@ interface orderItem {
interface print_group { interface print_group {
id: number, id: number,
name: string, name: string,
printer: number, printer_id: number,
venue_id: number, venue_id: number,
} }
@@ -50,21 +50,21 @@ interface floorplan_table {
id: number id: number
} }
interface decoration { interface floorplan_decoration {
id: number id: number
decoration_room: number room_id: number
decoration_pos_x: number pos_x: number
decoration_pos_y: number pos_y: number
decoration_rotation: number rotation: number
decoration_width: number width: number
decoration_height: number height: number
decoration_image: string image: string
venue_id: number venue_id: number
} }
interface room { interface room {
id: number id: number
room_name: string name: string
background_image: string background_image: string
venue_id: number venue_id: number
} }
@@ -87,26 +87,22 @@ interface keyboard {
} }
interface order_screen_page{id: number; order_screen_page_group_id: number; grid_id: number} interface order_screen_page{id: number; order_screen_page_group_id: number; grid_id: number}
interface grid {id: number; grid_name: string; grid_rows: number; grid_cols: number; grid_data: string} interface grid {id: number; name: string; rows: number; cols: number; data: string}
interface item { interface item {
id: number id: number
item_code: string code: string
item_category: number sales_category_id: number
item_name: string name: string
item_type: string item_type: string
price1: number price1: number
price2: number
price3: number
price4: number
price5: number
} }
type sales_category = { type sales_category = {
id: number id: number
parent: number parent: number
name: string name: string
print_group: string print_group_id: string
venue_id: number venue_id: number
} }

View File

@@ -1,9 +0,0 @@
<div id="alert" >
<div id="alertHeading"></div>
<div id="alertMessage"></div>
<div id="alertButtons">
<a class="posButton" id="alertOk"><!--[lang:alert_ok]--></a>
<a class="posButton" id="alertYes"><!--[lang:alert_yes]--></a>
<a class="posButton" id="alertNo"><!--[lang:alert_no]--></a>
</div>
</div>

View File

@@ -1,15 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title><!--[var:title]--></title>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name = "viewport" content = "user-scalable = no, initial-scale=0.8,maximum-scale=0.8 ,shrink-to-fit=yes" />
<link rel="manifest" href="/manifest.webmanifest">
</head>
<body>
<div id="authenticator">
</div>
<!--[template:keyboards]-->
</body>
</html>

View File

@@ -1,113 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>DredgePOS</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="stylesheet" type="text/css" href="themes/restaurant/theme.css?id=ax" media="screen" />
<link rel="stylesheet" type="text/css" href="themes/restaurant/paymentSplitter.css?id=ax" media="screen" />
<meta name = "viewport" content = "width=1280, initial-scale = 0.8, user-scalable = no, shrink-to-fit=no" />
<script type="text/javascript" src="currency.min.js"></script>
<script type="text/javascript" src="posFunctions.js"></script>
<script type="text/javascript" src="paymentFunctions.js"></script>
</head>
<body class="darkMode">
<div id="pageContainer">
<div id="flexWrapper">
<div id="header">
<h1>Paying Table</h2>
</div>
<div id="stucture">
<div id="leftColumn">
<h2>Whole Table</h2>
<table id="first" cellspacing="0">
<thead>
<th class="hide">Item Code</th>
<th>Qty</th>
<th>Item</th>
<th class="hide">Unit Price</th>
<th class="hide">Print Group</th>
<th class="totalpriceCell">Total Price</th>
<th class="hide">Cover</th>
<th class="clerkCell">Clerk</th>
<th class="hide">Selected Qty</th>
<th class="hide">Original Qty</th>
<th class="hide">Category</th>
<th class="hide">Department</th>
<th class="hide"><!--[lang:has_split_header]--></th>
<th class="hide"><!--[lang:orig_tprice_header]--></th>
</thead>
<tbody>
<!--[var:tableHTML]-->
</tbody>
</table>
</div>
<div id="controlColumn">
<a class="posButton" onclick="moveItems('#first', '#second')">&gt;</a>
<a class="posButton" onclick="moveItems('#second', '#first')">&lt;</a>
</div>
<div id="centerColumn">
<h2>Partial Table</h2>
<table id="second" cellspacing="0">
<thead>
<th class="hide">Item Code</th>
<th>Qty</th>
<th>Item</th>
<th class="hide">Unit Price</th>
<th class="hide">Print Group</th>
<th class="totalpriceCell">Total Price</th>
<th class="hide">Cover</th>
<th class="clerkCell hide">Clerk</th>
<th class="hide">Selected Qty</th>
<th class="hide">Category</th>
<th class="hide">Department</th>
<th class="hide"><!--[lang:has_split_header]--></th>
<th class="hide"><!--[lang:orig_tprice_header]--></th>
</thead>
<tbody>
</tbody>
</table>
</div>
<div id="rightColumn">
<h2>Controls</h2>
<div id="rightColumnContainer">
<a class="posButton heading" onclick="">Selection Tools</a>
<a class="posButton qtySelector" onclick="overrideQuantitySelect()">Select Quantity</a>
<a class="posButton" onclick="overrideQuantitySelect()">Select Amount</a>
<a class="selectDepartment posButton">Select By Department</a>
<a class="selectCategory posButton">Select By Category</a>
<a class="selectCovers posButton">Select by Cover #</a>
<a class="selectPrintGroup posButton">Select by Printed With</a>
<a class="selectAll posButton">Select All</a>
<a class="posButton heading">Select By Fraction</a>
<a class="posButton selectFraction" data-value="2">Select 12</a>
<a class="posButton selectFraction" data-value="3">Select 13</a>
<a class="posButton selectFraction" data-value="4">Select 14</a>
<a class="posButton selectFraction" data-value="5">Select 15</a>
<a class="posButton selectFraction" data-value="6">Select 16</a>
<a class="posButton selectFraction" data-value="7">Select 17</a>
<a class="posButton selectFraction" data-value="8">Select 18</a>
<a class="posButton selectFraction" data-value="<!--[var:uniqueCovers]-->" posButton">Select 1covers</a>
<a class="posButton heading" onclick="loadScreen('tableMap')">Exit</a>
</div>
</div>
</div>
</div>
</div>
<div id="coverControls" class="popupBox"><!--[var:coverButtons]--></div>
<div id="departmentControl" class="popupBox"><!--[var:departmentButtons]--></div>
<div id="categoryControl" class="popupBox"><!--[var:categoryButtons]--></div>
<div id="printGroupControl" class="popupBox"><!--[var:printGroupButtons]--></div>
<!--[template:keyboards]-->
<script type="text/javascript">
$(document).ready( function () {
covers = '<!--[var:covers]-->'
dredgePosSetup('#pageContainer');
setupPaymentSplitter();
} );
</script>
</body>
</html>

View File

@@ -1,14 +0,0 @@
<div class="itemCellWrapper">
<div
class="definedButton item <!--[arr:item|button_classes]--> posButton"
data-type="<!--[arr:item|type]-->"
data-id="<!--[arr:item|itemid]-->"
data-grid="<!--[arr:item|button_grid_id]-->"
data-name="<!--[arr:item|itemname]-->"
data-price="<!--[arr:item|price]-->"
data-category="<!--[arr:item|c_name]-->"
data-department="<!--[arr:item|dep_name]-->"
data-printgroup="<!--[arr:item|pg_name]-->">
<a><!--[arr:item|itemname]--></a>
</div>
</div>

View File

@@ -1,14 +0,0 @@
<div class="itemCellWrapper"> <div
class="definedButton item hasImage <!--[arr:item|button_classes]--> posButton"
data-type="<!--[arr:item|type]-->"
data-id="<!--[arr:item|itemid]-->"
data-name="<!--[arr:item|itemname]-->"
data-price="<!--[arr:item|price]-->"
data-grid="<!--[arr:item|button_grid_id]-->"
data-category="<!--[arr:item|c_name]-->"
data-department="<!--[arr:item|dep_name]-->"
data-printgroup="<!--[arr:item|pg_name]-->">
<a style="background-image:url('images/<!--[arr:item|image]-->')"></a>
<a><!--[arr:item|itemname]--></a>
</div></div>

View File

@@ -1,67 +0,0 @@
<div class="itemPage">
<table cellspacing="0" cellpadding="0">
<tr>
<td><!--[button:CRAFTBEER001]--></td>
<td><!--[button:CRAFTBEER002]--></td>
<td><!--[button:CRAFTBEER003]--></td>
<td><!--[button:CRAFTBEER004]--></td>
<td><!--[button:CRAFTBEER005]--></td>
<td><!--[button:CRAFTBEER006]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:CRAFTBEER007]--></td>
<td><!--[button:CRAFTBEER008]--></td>
<td><!--[button:CRAFTBEER009]--></td>
<td><!--[button:CRAFTBEER010]--></td>
<td><!--[button:CRAFTBEER012]--></td>
<td><!--[button:INSTRUCTION005]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td><!--[button:INSTRUCTION006]--></td>
</tr>
<tr>
<td><!--[button:CRAFTBEER013]--></td>
<td><!--[button:CRAFTBEER014]--></td>
<td><!--[button:CRAFTBEER015]--></td>
<td><!--[button:CRAFTBEER016]--></td>
<td><!--[button:CRAFTBEER017]--></td>
<td><!--[button:CRAFTBEER018]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:CRAFTBEER019]--></td>
<td><!--[button:CRAFTBEER020]--></td>
<td><!--[button:CRAFTBEER021]--></td>
<td><!--[button:CRAFTBEER022]--></td>
<td><!--[button:CRAFTBEER023]--></td>
<td><!--[button:CRAFTBEER024]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table></div>

View File

@@ -1,67 +0,0 @@
<div class="itemPage">
<table cellspacing="0" cellpadding="0">
<tr>
<td><!--[button:CRAFTBEER025]--></td>
<td><!--[button:CRAFTBEER026]--></td>
<td><!--[button:CRAFTBEER027]--></td>
<td><!--[button:CRAFTBEER028]--></td>
<td><!--[button:CRAFTBEER029]--></td>
<td><!--[button:CRAFTBEER030]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:CRAFTBEER031]--></td>
<td><!--[button:CRAFTBEER032]--></td>
<td><!--[button:CRAFTBEER033]--></td>
<td><!--[button:CRAFTBEER034]--></td>
<td><!--[button:CRAFTBEER035]--></td>
<td><!--[button:CRAFTBEER036]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:CRAFTBEER037]--></td>
<td><!--[button:CRAFTBEER038]--></td>
<td><!--[button:CRAFTBEER039]--></td>
<td><!--[button:CRAFTBEER040]--></td>
<td><!--[button:CRAFTBEER041]--></td>
<td><!--[button:CRAFTBEER042]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:CRAFTBEER043]--></td>
<td><!--[button:CRAFTBEER044]--></td>
<td><!--[button:CRAFTBEER045]--></td>
<td><!--[button:CRAFTBEER046]--></td>
<td><!--[button:CRAFTBEER047]--></td>
<td><!--[button:CRAFTBEER048]--></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table></div>

View File

@@ -1,66 +0,0 @@
<div class="itemPage"><table cellspacing="0" cellpadding="0">
<tr>
<td><!--[button:DESSERT001]--></td>
<td></td>
<td><!--[button:DESSERT002]--></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td><!--[button:DESSERT004]--></td>
<td></td>
<td><!--[button:DESSERT003]--></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table></div>

View File

@@ -1,67 +0,0 @@
<div class="itemPage"><table cellspacing="0" cellpadding="0">
<tr>
<td><!--[button:MAIN001]--></td>
<td></td>
<td><!--[button:MAIN003]--></td>
<td></td>
<td><!--[button:MAIN004]--></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:MAIN005]--></td>
<td></td>
<td><!--[button:MAIN006]--></td>
<td></td>
<td><!--[button:MAIN007]--></td>
<td></td>
</td>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table></div>

View File

@@ -1,68 +0,0 @@
<div class="itemPage">
<table cellspacing="0" cellpadding="0">
<tr>
<td><!--[button:STARTER001]--></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:STARTER002]--></td>
<td></td>
<td><!--[button:DIP002]--></td>
<td><!--[button:DIP003]--></td>
<td><!--[button:DIP004]--></td>
<td><!--[button:DIP005]--></td>
</tr>
<tr>
<td><!--[button:STARTER003]--></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:STARTER004]--></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><!--[button:STARTER005]--></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table></div>

View File

@@ -1,67 +0,0 @@
<div class="itemPage"><table cellspacing="0" cellpadding="0">
<tr>
<td></td>
<td></td>
<td><!--[button:WINE002]--></td>
<td><!--[button:WINE001]--></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td><!--[button:WINE004]--></td>
<td><!--[button:WINE003]--></td>
<td></td>
<td></td>
</td>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table></div>

View File

@@ -1,3 +0,0 @@
<a onclick="loadCategory('<!--[arr:cat|c_name]-->')" class="posButton categoryButton">
<!--[arr:cat|c_name]-->
</a>

View File

@@ -1,5 +0,0 @@
<!--[categoryButton:1]-->
<!--[categoryButton:2]-->
<!--[categoryButton:4]-->
<!--[categoryButton:3]-->
<!--[categoryButton:5]-->

View File

@@ -1,3 +0,0 @@
<a class="posButton <!--[var:classes]-->" <!--[var: attributes]-->>
<!--[var:text]-->
</a>

View File

@@ -1,4 +0,0 @@
<div class="decoratorItem" data-image="<!--[var:image_url]-->">
<a style="background-image:url('/images/decorations/<!--[var:image_url]-->')"></a>
<a><!--[var:image_name]--></a>
</div>

View File

@@ -1,3 +0,0 @@
<div class="decoratorRow">
<!--[var:decorations]-->
</div>

View File

@@ -1,79 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>DredgePOS</title>
<script src="https://unpkg.com/current-device/umd/current-device.min.js"></script>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name = "viewport" content = "user-scalable = no, initial-scale=0.8,maximum-scale=0.8 ,shrink-to-fit=yes" />
<link rel="manifest" href="/manifest.webmanifest">
</head>
<body class="darkMode">
<div id="pageContainer">
<div id="floorplanLeftColumn">
<div class="topCell">
<a class="posHeader">Logged in as <!--[arr:clerk|clerk_name]--></a>
</div>
<div class="middleCell">
</div>
<div class="bottomCell">
</div>
</div>
<div id="floorplanCenterColumn">
<div class="topCell">
<!--[var:roomMenu]-->
</div>
<div class="middleCell">
<div id="floorplanCanvas"></div>
</div>
<div class="bottomCell">
<div class="editControls" data-visible-in-mode='["tableSelected"]'>
<div class="posHeader currentTable">
<b class="selectedTableNumber"></b>
<a class="reservationStatus" data-visible-in-mode='["reservedTableSelected"]'></a>
<small class="selectedTableCovers"></small>
</div>
<a class="posButton placeOrderButton"><!--[lang:order_table]--></a>
<a class="posButton reserveTableButton" data-invisible-in-mode='["reservedTableSelected", "activeTableSelected"]'><!--[lang:reserve_table]--></a>
<a class="posButton unreserveTableButton" data-visible-in-mode='["reservedTableSelected"]'><!--[lang:unreserve_table]--></a>
<a class="posButton payTableButton" data-visible-in-mode='["activeTableSelected"]'><!--[lang:pay_table]--></a>
<a class="posButton viewTableButton" data-visible-in-mode='["activeTableSelected"]'><!--[lang:view_table]--></a>
</div>
</div>
</div>
<div id="floorplanRightColumn">
<div class="topCell">
<a class="posButton logOut" onclick="logout()">×</a>
</div>
<div class="middleCell">
<a class="posButton editModeButton"><!--[lang:edit_floorplan]--></a>
<div class="floorplanControls useVisibility" data-visible-in-mode='["edit"]'>
<a class="posButton addTableButton" ><!--[lang:add_table]--></a>
<a class="posButton addDecoration"><!--[lang:add_decoration]--></a>
<a class="posButton deleteDecoration useVisibility" data-visible-in-mode='["decorationSelected", "edit"]'><!--[lang:delete_decoration]--></a>
<a class="posButton deleteTableButton useVisibility" data-visible-in-mode='["tableSelected", "edit"]'><!--[lang:delete_table]--></a>
<a class="posButton changeShapeButton useVisibility" data-visible-in-mode='["tableSelected", "edit"]'><!--[lang:change_shape]--></a>
</div>
<div class="mergeControls useVisibility" data-visible-in-mode='["tableSelected"]'>
<a class="posButton mergeButton" data-active-in-mode="merge"><!--[lang:merge_table]--></a>
<a class="posButton unmergeButton" data-visible-in-mode='["tableSelected"]'><!--[lang:unmerge_table]--></a>
<a class="transferTableButton posButton" data-active-in-mode="transfer" data-visible-in-mode='["activeTableSelected"]'><!--[lang:transfer_table]--></a>
</div>
</div>
<div class="bottomCell">
</div>
</div>
</div>
<!--[template:keyboards]-->
<div id="decorator">
<div id="decoratorHeader">
<h2><!--[lang:choose_decoration]--></h2>
<a class="posButton" onclick="$('#decorator').css('display','none')">×</a>
</div>
<div id="decoratorContent"><!--[var:decorator]--></div>
</div>
</body>
</html>

View File

@@ -1,3 +0,0 @@
<!--[template:alert]-->
<!--[template:virtualNumpad]-->
<!--[template:virtualKeyboard]-->

View File

@@ -1 +0,0 @@
<b>OrderBox Loaded</b>

View File

@@ -1,21 +0,0 @@
<table cellspacing="0" id="orderBox" data-tablenumber="<!--[var:tableNumber]-->" data-covers="<!--[var:covers]-->" data-clerk="<!--[arr:clerk|clerk_name]-->" class="">
<thead>
<tr>
<th class="idCell hide"><!--[lang:id_header]--></th>
<th class="qtyCell"><!--[lang:qty_header]--></th>
<th class="itemCell"><!--[lang:item_header]--></th>
<th class="totalPriceCell"><!--[lang:total_price_header]--></th>
<th class="printGroupCell"><!--[lang:printgroup_header]--></th>
<th class="unitPriceCell hide"><!--[lang:individual_price_header]--></th>
<th class="sortkeyCell hide"><!--[lang:sortkey_header]--></th>
<th class="typeCell hide"><!--[lang:type_header]--></th>
<th class="coverCell hide"><!--[lang:cover_header]--></th>
<th class="departmentCell hide"><!--[lang:department_header]--></th>
<th class="categoryCell hide"><!--[lang:category_header]--></th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
</tfoot>
</table>

View File

@@ -1,107 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>DredgePOS</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="stylesheet" type="text/css" href="themes/restaurant/theme.css?id=ax" media="screen" />
<link rel="stylesheet" type="text/css" href="themes/restaurant/screen.css?id=ax" media="screen" />
<meta name = "viewport" content = "width=1280, initial-scale = 0.8, user-scalable = no, shrink-to-fit=no" />
<script type="text/javascript" src="posFunctions.js"></script>
</head>
<body class="darkMode">
<div id="pageContainer">
<div id="leftColumn">
<div id="tableDetails">
<h2><span id="activeTable"><!--[var:activeTable]--></span></h2>
<p class="posButton coverNumbers"><span id="covers"><!--[var:covers]--></span> covers </p>
<p class="clerk"><!--[var:loggedInAs]--></p>
</div>
<div id="orderBoxContainer">
<!--[template:orderBoxTable]-->
</div>
<div id="leftColumnFooter">
<p class="messageBox"></p>
<h2>Total Price: &nbsp; &nbsp;<span class="orderBoxTotals">$0.00</span></h2>
<p class="selectedTotal">($0.00 Selected)</p>
</div>
</div>
<div id="rightColumn">
<div id="topHalf">
<div id="courseSelect" class="posButtonGroup">
<h2><!--[lang:print_with]--></h2>
<a onclick="setPrintGroupOverride(false, this)" class="toggle default posButton active"><!--[lang:print_with_category|default]--></a>
<a onclick="setPrintGroupOverride('Starters',this)" class="posButton toggle"><!--[lang:print_with_category|Starters]--></a>
<a onclick="setPrintGroupOverride('Mains',this)" class="posButton toggle"><!--[lang:print_with_category|Mains]--></a>
<a onclick="setPrintGroupOverride('Desserts',this)" class="posButton toggle"><!--[lang:print_with_category|Desserts]--></a>
<a onclick="setPrintGroupOverride('Drinks',this)" class="posButton toggle"><!--[lang:print_with_category|Drinks]--></a>
</div>
<div id="functions">
<h2><!--[lang:functions_header]--></h2>
<a onclick="loadScreen('tableMap')" class="posButton"><!--[lang:close_order_function]--></a>
<a class="posButton accumulateButton"><!--[lang:accumulate_function]--></a>
<a class="posButton void"><!--[lang:void]--></a>
<a class="posButton"><!--[lang:pay_function]--></a>
<a class="posButton saveOrder"><!--[lang:print_function]--></a>
</div>
<div id="positionControl">
<a class="posButton freeText" data-type="instruction" data-id="freetext"
data-name=""
data-price="0"
data-category="0"
data-department="0"
data-printgroup="0"><!--[lang:freetext_button]--></a>
<div type="text" class="positionInput"><!--[lang:select_covers]--></div>
<div id="positions">
</div>
</form>
</div>
<div id="topNumPad" class="numPad">
<a class="posButton numberButton">1</a>
<a class="posButton numberButton">2</a>
<a class="posButton numberButton">3</a>
<a class="posButton numberButton">4</a>
<a class="posButton numberButton">5</a>
<a class="posButton numberButton">6</a>
<a class="posButton numberButton">7</a>
<a class="posButton numberButton">8</a>
<a class="posButton numberButton">9</a>
<a class="posButton numberButton">0</a>
<a class="posButton numberButton">.</a>
<a class="posButton multiplier">×</a>
</div>
</div>
<div id="bottomHalf">
<!--[template:categoryMenu]-->
<div id="itemGrid">
<div id="itemWrapper">
<!--[template:categories/StartersPage1]-->
</div>
</div>
<div id="innerNavigation">
<a class="posButton" onclick="scrollPage('left')">&lt;</a>
<a class="posButton" onclick="scrollPage('right')">&gt;</a>
</div>
</div>
</div>
</div>
<!--[template:keyboards]-->
<script type="text/javascript">
$(document).ready( function () {
//Base grid width must be defined for multipage functionality to work.
baseGridWidth = 850;
dredgePosSetup();
$("#orderBox tbody tr").on( 'click', function ( e ) {
selectRow($(this));
} )
} );
</script>
</body>
</html>

View File

@@ -1,84 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>DredgePOS</title>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name = "viewport" content = "user-scalable = no ,shrink-to-fit=yes" />
<link rel="manifest" href="/manifest.webmanifest">
</head>
<body>
<div id="pageContainer" <!--[var: containerAttributes]-->>
<div id="leftColumn">
<h1 class="tableHeading"><!--[var: orderNumber]--></h1>
<div class="tableInfo">
<!--[var: changeCoverNumberButton]-->
<a class="posButton">Logged in as <!--[arr:clerk|clerk_name]--></a>
</div>
<div class="orderBox">
<table class="orderBoxTable">
<thead>
<tr>
<th class="orderBoxCell qtyCell"><!--[lang:qty_header]--></th>
<th class="orderBoxCell itemIdCell hidden"><!--[lang:id_header]--></th>
<th class="orderBoxCell itemCell"><!--[lang:item_header]--></th>
<th class="orderBoxCell unitPriceCell hidden"><!--[lang:price_header]--></th>
<th class="orderBoxCell totalPriceCell"><!--[lang:total_price_header]--></th>
<th class="orderBoxCell printGroupCell"><!--[lang:printgroup_header]--></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<div class="orderBoxInfo">
<span class="voidModeWarning" data-visible-in-mode='["void"]'><!--[lang:void_mode]--></span>
</div>
<div class="orderBoxFooter">
<span class="orderBoxTotal"><!--[lang:totalPrice|0.00]--></span>
<small class="orderBoxSelectedTotal"><!--[lang:selectedPrice|0.00]--></small>
</div>
</div>
<div id="rightColumn">
<div id="topHalf">
<div class="functionButtons">
<div class="printGroupButtons toggleGroup">
<input type="hidden" name="print_override" class="value" />
<!--[var:salesCategoryOverrideButtons]-->
</div>
<div class="functionColumn">
<a class="posButton accumulateButton" data-active-in-mode="accumulate"><!--[lang:accumulate_function]--></a>
<a class="showCoverSelectorButton posButton"><!--[lang:select_covers]--></a>
</div>
<div class="functionColumn">
<a class="posButton voidButton" data-active-in-mode="void"><!--[lang:void]--></a>
<a class="posButton openItemButton"><!--[lang:custom_item_button]--></a>
<a class="freetextButton posButton"><!--[lang:freetext_button]--></a>
<a class="numpadButton posButton"><!--[lang:numpad_button]--></a>
</div>
<div class="functionColumn">
<a class="posButton"><!--[lang:pay_function]--></a>
<a class="posButton"><!--[lang:print_function]--></a>
</div>
</div>
</div>
<div id="pageList">
<!--[var:categoryList]-->
</div>
<div id="pageGroupContainer">
<!--[var:pageGroups]-->
</div>
<div class="pageNavigation">
<a class="posButton prevButton"><!--[lang:prev_page]--></a>
<a class="posButton nextButton"><!--[lang:next_page]--></a>
</div>
</div>
</div>
<!--[template:keyboards]-->
<!--[template:orderScreen/grid_container]-->
<!--[template:orderScreen/cover_selector]-->
<template id="posButtonTemplate">
<!--[template:components/posButton]-->
</template>
</body>
</html>

View File

@@ -1 +0,0 @@
<span class="buttonImg" style="background-image:url(/images/items/<!--[var:image]-->);"></span>

View File

@@ -1 +0,0 @@
<a href="#" class="posButton changeCoverNumberButton"><!--[var:covers]--></a>

View File

@@ -1,3 +0,0 @@
<div class="coverSelector">
<!--[var:coverSelectorButtons]-->
</div>

View File

@@ -1,6 +0,0 @@
<a href="#" class="posButton <!--[var:extra_classes]-->"
data-primary-action="<!--[var:primary_action]-->"
data-secondary-action="<!--[var:secondary_action]-->" <!--[var: extra_data]--> <!--[var: extra_styles]-->>
<!--[var:image]-->
<span class="text"><!--[var:text]--></span>
</a>

View File

@@ -1,13 +0,0 @@
<div class="gridContainer">
<div class="gridContainerHeader">
<span></span>
<div class="posButton closeGrid">×</div>
</div>
<div class="gridContainerGrid">
<div class="pageGroup"></div>
</div>
<div class="pageNavigation">
<a class="posButton prevButton"><!--[lang:prev_page]--></a>
<a class="posButton nextButton"><!--[lang:next_page]--></a>
</div>
</div>

View File

@@ -1,6 +0,0 @@
<div class="gridPage" style="
grid-template-columns: repeat(<!--[var:cols]-->, 1fr);
grid-template-rows: repeat(<!--[var:rows]-->, 1fr);
">
<!--[var:pageButtons]-->
</div>

View File

@@ -1,3 +0,0 @@
<div class="pageGroup" data-page-group-id="<!--[var:page_group_id]-->">
<!--[var:pages]-->
</div>

View File

@@ -1,3 +0,0 @@
<a data-page-group-id="<!--[arr:page|id]-->" class="posButton loadPageGroup">
<!--[arr:page|label]-->
</a>

View File

@@ -1,157 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>DredgePOS</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://unpkg.com/current-device/umd/current-device.min.js"></script>
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="stylesheet" type="text/css" href="themes/restaurant/theme.css?id=ax" media="screen" />
<link rel="stylesheet" type="text/css" href="themes/restaurant/paymentSplitter.css?id=ax" media="screen" />
<meta name = "viewport" content = "user-scalable = no, initial-scale=0.8 ,shrink-to-fit=yes" />
<script type="text/javascript" src="currency.min.js"></script>
<script type="text/javascript" src="posFunctions.js"></script>
<script type="text/javascript" src="paymentFunctions.js"></script>
</head>
<body class="darkMode" data-tablenumber="<!--[var:activeTable]-->">
<div id="pageContainer">
<div id="flexWrapper">
<div id="header">
<a class="posButton"><!--[var:loggedInAs]--></a>
<h1><!--[lang:paying_table|<!--[var:activeTable]-->]--></h1>
<a class="posButton exit" onclick="loadScreen('tableMap')">×</a>
</div>
<div id="pageStructure">
<div id="leftColumn">
<h2>Whole Table</h2>
<div class="tableWrapper">
<table id="first" cellspacing="0">
<thead>
<th class="hide"><!--[lang:id_header]--></th>
<th><!--[lang:qty_header]--></th>
<th><!--[lang:item_header]--></th>
<th class="hide"><!--[lang:individual_price_header]--></th>
<th class="hide"><!--[lang:printgroup_header]--></th>
<th class="totalpriceCell"><!--[lang:total_price_header]--></th>
<th class="hide"><!--[lang:cover_header]--></th>
<th class="clerkCell"><!--[lang:clerk_header]--></th>
<th class="hide"><!--[lang:orig_qty_header]--></th>
<th class="hide"><!--[lang:category_header]--></th>
<th class="hide"><!--[lang:department_header]--></th>
<th class="hide"><!--[lang:orig_tprice_header]--></th>
</thead>
<tbody>
<!--[var:tableHTML]-->
</tbody>
</table>
</div>
<div class="tableFooter">
<div class="totalsRow">
<h3 class="firstTotal"></h3>
<p class="firstSelectedTotal"></p>
</div>
<div class="controlRow">
<a class="posButton payAll"><!--[lang:pay_all]--></a>
</div>
</div>
</div>
<div id="controlColumn">
<a class="posButton" onclick="moveItems('#first', '#second')">&gt;</a>
<a class="posButton" onclick="moveItems('#second', '#first')">&lt;</a>
</div>
<div id="centerColumn">
<h2>Partial Table</h2>
<div class="tableWrapper">
<table id="second" cellspacing="0">
<thead>
<th class="hide"><!--[lang:id_header]--></th>
<th><!--[lang:qty_header]--></th>
<th><!--[lang:item_header]--></th>
<th class="hide"><!--[lang:individual_price_header]--></th>
<th class="hide"><!--[lang:printgroup_header]--></th>
<th class="totalpriceCell"><!--[lang:total_price_header]--></th>
<th class="hide"><!--[lang:cover_header]--></th>
<th class="clerkCell"><!--[lang:clerk_header]--></th>
<th class="hide"><!--[lang:orig_qty_header]--></th>
<th class="hide"><!--[lang:category_header]--></th>
<th class="hide"><!--[lang:department_header]--></th>
<th class="hide"><!--[lang:orig_tprice_header]--></th>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="tableFooter">
<div class="totalsRow">
<h3 class="secondTotal"></h3>
<p class="secondSelectedTotal"></p>
</div>
<div class="controlRow">
<a class="posButton payPartial"><!--[lang:pay_table]--></a>
<a class="posButton transferPartial">Transfer to Another Table</a>
<a class="posButton selectAllSecond">Select All</a>
</div>
</div>
</div>
<div id="rightColumn">
<h2>Controls</h2>
<div id="rightColumnContainer">
<div class="row">
<a class="heading" onclick="">Selection Tools</a>
</div>
<div class="row">
<a class="posButton qtySelector">Select Quantity</a>
<a class="posButton selectAmount">Select Amount</a>
</div>
<div class="row">
<a class="selectDepartment posButton">Select By Department</a>
<a class="selectCategory posButton">Select By Category</a>
</div>
<div class="row">
<a class="selectCovers posButton">Select by Cover #</a>
<a class="selectPrintGroup posButton">Select by Printed With</a>
</div>
<div class="row">
<a class="selectAll posButton">Select All</a>
</div>
<div class="row">
<a class="heading">Select By Fraction</a>
</div>
<div class="row">
<a class="posButton selectFraction" data-value="2">Select 12</a>
<a class="posButton selectFraction" data-value="3">Select 13</a>
</div>
<div class="row">
<a class="posButton selectFraction" data-value="4">Select 14</a>
<a class="posButton selectFraction" data-value="5">Select 15</a>
</div>
<div class="row">
<a class="posButton selectFraction" data-value="6">Select 16</a>
<a class="posButton selectFraction" data-value="7">Select 17</a>
</div>
<div class="row">
<a class="posButton selectFraction" data-value="8">Select 18</a>
<a class="posButton selectFraction" data-value="<!--[var:covers]-->">Select 1covers</a>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="coverControls" class="popupBox"><!--[var:coverButtons]--></div>
<div id="departmentControl" class="popupBox"><!--[var:departmentButtons]--></div>
<div id="categoryControl" class="popupBox"><!--[var:categoryButtons]--></div>
<div id="printGroupControl" class="popupBox"><!--[var:printGroupButtons]--></div>
<!--[template:keyboards]-->
<script type="text/javascript">
$(document).ready( function () {
covers = '<!--[var:covers]-->'
dredgePosSetup('#pageContainer');
setupPaymentSplitter();
} );
</script>
</body>
</html>

View File

@@ -1 +0,0 @@
<a data-value="<!--[var:value]-->" class="posButton <!--[var:class]-->"><!--[var:text]--></a>

View File

@@ -1 +0,0 @@
<a class="posButton roomButton" data-value="<!--[var:roomId]-->"><!--[var:roomName]--></a>

View File

@@ -1,71 +0,0 @@
<div id="virtualKeyboard">
<div class="headingRow">
<h3 id="virtualKeyboardHeading"></h3>
<a class="posButton closeKeyboards">X</a>
</div>
<input type="text" name="virtualKeyboardInput" id="virtualKeyboardInput" />
<div id="virtualKeyboardButtons">
<div class="virtualKeyboardRow">
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
</div>
<div class="virtualKeyboardRow">
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
</div>
<div class="virtualKeyboardRow">
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
</div>
<div class="virtualKeyboardRow">
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
<a></a>
</div>
<div class="virtualKeyboardRow">
<a></a>
</div>
<span class="forceFocus"></span>
</div>
</div>

View File

@@ -1,28 +0,0 @@
<div id="virtualNumpad">
<div class="headingRow">
<h3 id="virtualNumpadHeading"></h3>
<a class="posButton closeKeyboards">X</a>
</div>
<div id="virtualNumpadInput"></div>
<div id="virtualNumpadButtons">
<div class="virtualNumpadRow">
<a href="#" data-value="1" class="posButton virtualNumpadButton">1</a>
<a href="#" data-value="2" class="posButton virtualNumpadButton">2</a>
<a href="#" data-value="3" class="posButton virtualNumpadButton">3</a>
</div><div class="virtualNumpadRow">
<a href="#" data-value="4" class="posButton virtualNumpadButton">4</a>
<a href="#" data-value="5" class="posButton virtualNumpadButton">5</a>
<a href="#" data-value="6" class="posButton virtualNumpadButton">6</a>
</div><div class="virtualNumpadRow">
<a href="#" data-value="7" class="posButton virtualNumpadButton">7</a>
<a href="#" data-value="8" class="posButton virtualNumpadButton">8</a>
<a href="#" data-value="9" class="posButton virtualNumpadButton">9</a>
</div><div class="virtualNumpadRow">
<a href="#" data-value="0" class="posButton virtualNumpadButton">0</a>
<a href="#" data-value="." class="posButton virtualNumpadButton">.</a>
<a href="#" data-value="clear" class="posButton virtualNumpadButton virtualNumpadClear">Clear</a>
</div><div class="virtualNumpadRow">
<a href="#" data-value="submit" class="posButton virtualNumpadButton virtualNumpadSubmit">Enter</a>
</div>
</div>
</div>

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Some files were not shown because too many files have changed in this diff Show More