Floorplan Updated

This commit is contained in:
2021-11-09 17:16:29 +10:00
parent 49fcdabf0f
commit 61481ad87c
37 changed files with 1862 additions and 1762 deletions

View File

@@ -1 +0,0 @@
DredgePos

View File

@@ -156,7 +156,7 @@
<virtualDirectoryDefaults allowSubDirConfig="true" />
<site name="DredgePos" id="1">
<application path="/" applicationPool="DredgePos AppPool">
<virtualDirectory path="/" physicalPath="C:\Users\dredgy\RiderProjects\WebApplication\WebApplication" />
<virtualDirectory path="/" physicalPath="C:\Users\dredgy\RiderProjects\DredgePos\DredgePos" />
</application>
<bindings>
<binding protocol="http" bindingInformation="*:55543:localhost" />
@@ -974,7 +974,7 @@
</system.webServer>
</location>
<location path="DredgePos" inheritInChildApplications="false">
<system.webServer>
<system.webServer>
<security>
<authentication>
<anonymousAuthentication enabled="true" />
@@ -984,11 +984,16 @@
<handlers>
<add name="aspNetCore" path="*" verb="*" resourceType="Unspecified" modules="aspnetcorev2" />
</handlers>
<modules><add name="aspnetcorev2" /><remove name="WebMatrixSupportModule" /></modules>
<modules>
<add name="aspnetcorev2" />
<remove name="WebMatrixSupportModule" />
</modules>
<aspNetCore stdoutLogEnabled="false" startupTimeLimit="3600" requestTimeout="23:00:00" processPath="%ANCM_LAUNCHER_PATH%" hostingModel="InProcess" arguments="%ANCM_LAUNCHER_ARGS%" />
<httpCompression>
<dynamicTypes><add mimeType="text/event-stream" enabled="false" /></dynamicTypes>
<dynamicTypes>
<add mimeType="text/event-stream" enabled="false" />
</dynamicTypes>
</httpCompression>
</system.webServer>
</location>
</system.webServer>
</location>
</configuration>

View File

@@ -1,9 +1,12 @@
module AjaxController
open DredgeFramework
open Floorplan
open Microsoft.AspNetCore.Http
open Reservations
open language
open Giraffe
open Dapper.FSharp
let loginWithLoginCode (context: HttpContext) (login_code: int) =
if Session.clerkLogin login_code context then ajaxSuccess "success"
@@ -15,28 +18,50 @@ let getActiveTables venue = Floorplan.getActiveTables venue |> ajaxSuccess |> js
let getRoomData roomId = Floorplan.getRoom roomId |> ajaxSuccess |> json
let mergeTables (parent, child) =
let mergeTables (tables: floorplan_table[]) =
let status =
if Floorplan.mergeTables parent child then "success"
else "fail"
map [
"status", status
"data" , parent |> Floorplan.getTable |> jsonEncode
if mergeTables tables.[0].table_number tables.[1].table_number then
let outputTables = map [
"parent", tables.[0];
"child", tables.[1];
"merged", getTable tables.[0].table_number;
]
|> json
ajaxSuccess outputTables
else ajaxFail "Could Not Merge Tables"
status |> json
let unmergeTable tableNumber =
let status =
if Floorplan.unmergeTable tableNumber then "success"
else "fail"
let unmerged = Floorplan.unmergeTable tableNumber
let unmergedTables =
match unmerged with
| Some (parent, child) ->
map["parent", parent; "child", child] |> ajaxSuccess
| None -> ajaxFail "Could not Unmerge Table"
map [
"status", status
"data" , "[true]"
]
unmergedTables |> json
let getFloorplanData venue =
let tableList = Floorplan.tableList venue
let reservationList = getReservationList tableList
{|
tables = tableList
decorations = Decorations.decorationList venue
activeTableNumbers = Floorplan.getActiveTables venue
rooms = Floorplan.getRoomList venue
reservations = reservationList
|}
|> ajaxSuccess
|> json
let getKeyboardLayout (language: string) =
let layout = $"""wwwroot/languages/{language}/keyboardLayout.json""" |> GetFileContents
map [
"status", "success"
"data", layout
] |> json
let getRoomTablesAndDecorations roomId =
let tables = Floorplan.tablesInRoom roomId
let decorations = Decorations.decorationsInRoom roomId
@@ -53,50 +78,70 @@ let updateTableShape (table: Floorplan.floorplan_table_shape) =
Floorplan.updateTableShape table |> ignore
getTableData table.table_number
let transformTable (table: Floorplan.floorplan_table_transform) =
let transformTable (table: Floorplan.floorplan_table) =
Floorplan.updateTablePosition table |> ignore
getTableData table.table_number
let createTable (tableData) =
let newTableCreated = Floorplan.addNewTable tableData
let createTable (tableData: floorplan_table) =
let result =
if newTableCreated then Floorplan.getTable tableData.table_number |> jsonEncode |> ajaxSuccess
else Floorplan.tableExists tableData.table_number |> jsonEncode |> ajaxFail
if tableExists tableData.table_number = "False" then
ajaxSuccess (addNewTable tableData)
else ajaxFail (tableExists tableData.table_number)
json result
result |> json
let deleteTable (table: floorplan_table) =
Floorplan.deleteTable table.table_number
table |> ajaxSuccess |> json
let transferTable (origin, destination) =
Floorplan.transferTable origin destination
ajaxSuccess "true" |> json
let data = map ["origin", getTable origin ; "destination", getTable destination]
ajaxSuccess data |> json
let AddDecoration (data: Decorations.decoration_creator) =
let AddDecoration (data: Decorations.floorplan_decoration) =
let image = "wwwroot/images/decorations/" + data.decoration_image
let width, height = image |> GetImageSize
let aspectRatio = decimal width / decimal height
let decoration : Decorations.floorplan_decoration = {
decoration_id = 0
id = 0
decoration_height = (200m / aspectRatio) |> int
decoration_width = 200
decoration_rotation = 0
decoration_image = data.decoration_image
decoration_pos_x = data.basis/2
decoration_pos_y = data.basis/2
decoration_pos_x = data.decoration_pos_x
decoration_pos_y = data.decoration_pos_y
decoration_room = data.decoration_room
}
Decorations.CreateDecoration decoration |> ignore
ajaxSuccess "true" |> json
Decorations.CreateDecoration decoration |> ajaxSuccess |> json
let UpdateDecoration data =
Decorations.UpdateDecoration data |> ignore
ajaxSuccess "true" |> json
let DeleteDecoration id =
Decorations.DeleteDecorationById id |> ignore
ajaxSuccess "true" |> json
let DeleteDecoration id = ajaxSuccess (Decorations.DeleteDecoration id) |> json
let newEmptyReservation tableNumber =
Floorplan.createEmptyReservation tableNumber 2
let newEmptyReservation (reservation: reservation) =
let newReservation = {reservation with
reservation_created_at = CurrentTime()
reservation_time = CurrentTime()
}
json <| ajaxSuccess "true"
if reservation.reservation_table_id > 0 then
let table = {(getTableById reservation.reservation_table_id) with
status = 2
default_covers = reservation.reservation_covers}
updateTablePosition table |> ignore
let createdReservation = Floorplan.createEmptyReservation newReservation
ajaxSuccess createdReservation |> json
let updateReservation (reservation: reservation) = updateReservation reservation |> ajaxSuccess |> json
let unreserveTable (table: floorplan_table) =
let newTable = {table with status = 0}
updateTablePosition newTable |> ignore
DeleteReservation newTable.id
newTable |> ajaxSuccess |> json

View File

@@ -8,12 +8,12 @@ open Thoth.Json.Net
let mutable loginCookie = ""
type clerk = {clerk_id: int; clerk_name: string; clerk_login_code: int; clerk_usergroup: int}
type clerk = {id: int; clerk_name: string; clerk_login_code: int; clerk_usergroup: int}
let clerk_decoder : Decoder<clerk> =
Decode.object
(fun get ->
{
clerk_id = get.Required.Field "clerk_id" Decode.int
id = get.Required.Field "clerk_id" Decode.int
clerk_name = get.Required.Field "clerk_name" Decode.string
clerk_login_code = get.Required.Field "clerk_login_code" Decode.int
clerk_usergroup = get.Required.Field "clerk_usergroup" Decode.int

View File

@@ -1,5 +1,7 @@
module db
open Dapper
open Dapper.FSharp
open Dapper.FSharp.MySQL
open MySql.Data.MySqlClient
open DredgeFramework
@@ -24,6 +26,16 @@ let Insert<'a> asyncQuery =
|> connection.InsertAsync<'a>
|> RunSynchronously
let InsertOutput<'a> asyncQuery =
asyncQuery
|> connection.InsertAsync<'a>
|> RunSynchronously
|> ignore
let table = asyncQuery.Table
connection.Query<'a>($"""Select * From {table} Where id = (select last_insert_id())""")
|> EnumerableToArray
let Update<'a> asyncQuery =
asyncQuery
|> connection.UpdateAsync<'a>

View File

@@ -6,10 +6,11 @@ open System.Text.RegularExpressions
open DredgeFramework
open Dapper
open Dapper.FSharp
open Floorplan
[<CLIMutable>]
type floorplan_decoration = {
decoration_id: int
id: int
decoration_room: int
decoration_pos_x: int
decoration_pos_y: int
@@ -19,12 +20,14 @@ type floorplan_decoration = {
decoration_image: string
}
type decoration_creator = {
decoration_room: int
decoration_image: string
basis: int
}
let decorationList venue =
select {
table "floorplan_decorations"
innerJoin "floorplan_rooms" "id" "decoration_room"
}
|> db.SelectJoin<floorplan_decoration, floorplan_room>
|> Array.filter (fun (_, room) -> room.venue_id = venue )
|> Array.map fst
let decorationsInRoom (roomId: int) =
select {
@@ -43,8 +46,6 @@ let getImageName (image: string, path: string) =
imageName, path
let isImageFile (fileName: string) = Regex.IsMatch(fileName |> ToLowerCase, @"^.+\.(jpg|jpeg|png|gif)$")
let getImageHTML (imageName: string, imageUrl: string) =
@@ -77,20 +78,21 @@ let CreateDecoration (decoration: floorplan_decoration) =
insert {
table "floorplan_decorations"
value decoration
} |> db.Insert
}
|> db.InsertOutput
|> first
let UpdateDecoration (decoration: floorplan_decoration) =
let imageFile = GetFileName decoration.decoration_image
let updatedDecoration = {decoration with decoration_image = imageFile}
update {
table "floorplan_decorations"
set updatedDecoration
where (eq "decoration_id" decoration.decoration_id )
set decoration
where (eq "id" decoration.id )
} |> db.Update
let DeleteDecorationById (id: int) =
let DeleteDecoration (decoration: floorplan_decoration) =
delete {
table "floorplan_decorations"
where (eq "decoration_id" id)
} |> db.Delete
where (eq "id" decoration.id)
} |> db.Delete |> ignore
decoration

View File

@@ -18,9 +18,7 @@ let (|?) lhs rhs = if lhs = null then rhs else lhs
let map list = list |> Map.ofList
let JoinArray (char: string) (array: string[]) = String.Join(char, array)
let first (array: 'a[]) = array.[0]
let JoinArray (char: string) (array: 'a[]) = String.Join(char, array)
let StringReplace (search:string) (replace:string) (string:string) = (search, replace) |> string.Replace
@@ -37,6 +35,9 @@ let GetFileContents (file: string) = File.ReadAllText file
let GetFileName (file: string) = Path.GetFileName file
let length (variable: 'T[]) = variable.Length
let first (array: 'a[]) = array.[0]
let last (array: 'a[]) = array.[array.Length-1]
let removeFalseValues (variable: bool[]) = variable |> Array.filter id
@@ -67,14 +68,15 @@ let RunSynchronously task =
|> Async.AwaitTask
|> Async.RunSynchronously
let AppendToArray (element: 'T) (array : 'T[]) = Array.append [|element|] array
let ToLowerCase (string: string) = string.ToLower()
let ToUpperCase (string: string) = string.ToUpper()
let ToTitleCase (string: string) = CultureInfo.CurrentCulture.TextInfo.ToTitleCase <| string
let recordToMap (record: 'T) =
seq {
for prop in FSharpType.GetRecordFields(typeof<'T>) ->
prop.Name, prop.GetValue(record) |> string
for prop in FSharpType.GetRecordFields(typeof<'T>) -> prop.Name, prop.GetValue(record) |> string
}
|> Map.ofSeq

View File

@@ -9,6 +9,7 @@
<Compile Include="Browser.module.fs" />
<Compile Include="Database.module.fs" />
<Compile Include="Language.module.fs" />
<Compile Include="GenericEntities.module.fs" />
<Compile Include="Theme.module.fs" />
<Compile Include="Reservations.module.fs" />
<Compile Include="Floorplan.module.fs" />
@@ -31,6 +32,7 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Remove="node_modules\**" />
<Content Remove="wwwroot\scripts\ts\test.ts" />
</ItemGroup>
<ItemGroup>

View File

@@ -38,13 +38,13 @@ type floorplan_table = {
rotation: int
merged_children: string
previous_state: string
status: string
table_id: int
status: int
id: int
}
[<CLIMutable>]
type floorplan_room = {
room_id: int
id: int
room_name: string
background_image: string
venue_id: int
@@ -66,8 +66,8 @@ let floorplan_table_decoder : Decoder<floorplan_table> =
rotation = get.Required.Field "rotation" Decode.int
merged_children = get.Required.Field "merged_children" Decode.string
previous_state = get.Required.Field "previous_state" Decode.string
status = get.Required.Field "status" Decode.string
table_id = get.Required.Field "table_id" Decode.int
status = get.Required.Field "status" Decode.int
id = get.Required.Field "id" Decode.int
})
@@ -78,10 +78,12 @@ let getTableFile (tableNumber: int) =
let tableNumberString = tableNumber |> string
activeTablePath + "table" + tableNumberString + ".table"
let tableIsOpen (tableNumber: int) =
let tableNumberIsOpen (tableNumber: int) =
let tableFile = getTableFile tableNumber
File.Exists tableFile
let tableIsOpen (table: floorplan_table) = tableNumberIsOpen table.table_number
let fileNameToTableNumber (fileName: string) = //Takes a file name for a floorplan table and returns the table number
if fileName.Contains ".table" then
let fileName = (fileName.Split ".").[0]
@@ -105,15 +107,14 @@ let tablesInRoom (roomId: int) = //Get a list of all tables in a particular room
|> db.Select<floorplan_table>
let getActiveTables (venueId: int) =
select{
table "floorplan_tables"
where (eq "venue_id" venueId)
}
|> db.Select
|> Array.map getTableNumber
|> Array.filter tableIsOpen
|> Array.map (fun table -> table.table_number)
let openNewTable tableNumber = //Create a new table file pre-populated with skeleton data
let tableFile = getTableFile tableNumber
@@ -128,10 +129,10 @@ let transferTable origin destination = //Transfers a table from one to another
let originFile = getTableFile origin
let destinationFile = getTableFile destination
if tableIsOpen origin then
if tableNumberIsOpen origin then
(* If the destination is not an already open table,
then we simply have to rename the origin to destination *)
if not <| tableIsOpen destination then
if not <| tableNumberIsOpen destination then
let content = File.ReadAllText originFile
let newContent = content.Replace($"number=\"{origin|>string}\">", $"number=\"{destination|>string}\">")
File.WriteAllText(originFile, newContent)
@@ -159,10 +160,18 @@ let getTable (tableNumber : int) =
|> db.Select<floorplan_table>
|> first
let getTableById (id : int) =
select {
table "floorplan_tables"
where (eq "id" id)
}
|> db.Select<floorplan_table>
|> first
let getRoom (roomId: int) =
select {
table "floorplan_rooms"
where (eq "room_id" roomId)
where (eq "id" roomId)
} |> db.Select<floorplan_room> |> first
let getRoomList (venueId: int) =
@@ -172,6 +181,7 @@ let getRoomList (venueId: int) =
} |> db.Select<floorplan_room>
let updateFloorplanTable (tableNumber:int) (column: string) value =
//TODO: Make update query venue specific
let sql = "Update floorplan_tables Set @column = @value Where table_number = @tableNumber"
let parameters = [("column", box column); ("value", box value); ("tableNumber", box tableNumber)]
db.connection.Execute(sql, parameters) |> ignore
@@ -185,25 +195,26 @@ let updateTableShape (floorplanTable: floorplan_table_shape) =
where (eq "table_number" floorplanTable.table_number + eq "venue_id" currentVenue)
} |> db.Update
let updateTablePosition (floorplanTable: floorplan_table_transform) =
let updateTablePosition (floorplanTable: floorplan_table) =
update {
table "floorplan_tables"
set floorplanTable
where (eq "table_number" floorplanTable.table_number + eq "venue_id" currentVenue)
} |> db.Update
let createEmptyReservation tableNumber covers =
let table = getTable tableNumber
let status = if table.status = "" then "reserved" else table.status
//let res = newReservation "" 0 covers
update{
let createEmptyReservation (reservation: reservation) =
update {
table "floorplan_tables"
set {| status = status |}
where(eq "table_number" tableNumber)
set {| status = 2 |}
where(eq "id" reservation.reservation_table_id)
} |> db.Update |> ignore
insert{
table "reservations"
value reservation
} |> db.InsertOutput |> first
let getChildTables tableNumber =
@@ -217,7 +228,7 @@ let matchTable (tableNumberToMatch: int) (floorplanTableToCheck: floorplan_table
let findChildTable (childTable: int) (parentTable: floorplan_table) =
let json = parentTable.merged_children
let childTables = json |> Decode.fromString(Decode.array floorplan_table_decoder)
let childTables = json |> Decode.Auto.fromString<floorplan_table[]>
let matchedTables =
match childTables with
@@ -262,16 +273,24 @@ let tableExists (tableNumber: int) =
language.getAndReplace "error_table_exists" [room.room_name]
let addNewTable newTable =
if tableExists newTable.table_number = "False" then
let addNewTableWithoutOutput (newTable: floorplan_table) =
insert{
table "floorplan_tables"
value newTable
} |> db.Insert |> ignore
true
else false
}
|> db.Insert
let deleteTable tableNumber =
let addNewTable (newTable: floorplan_table) =
let newTableList =
insert{
table "floorplan_tables"
value newTable
}
|> db.InsertOutput
newTableList |> first
let deleteTable (tableNumber: int) =
delete {
table "floorplan_tables"
where (eq "table_number" tableNumber + eq "venue_id" currentVenue)
@@ -342,7 +361,7 @@ let updateUnmergedTables parentTable childTable =
where(eq "table_number" parentTable.table_number + eq "venue_id" currentVenue)
} |> db.Update |> ignore
addNewTable childTable |> ignore
addNewTableWithoutOutput childTable |> ignore
true
let processUnmerge originalTable unmergedChild =
@@ -354,25 +373,35 @@ let processUnmerge originalTable unmergedChild =
let unmergeTable tableNumber = //Separates a merged table into itself and the last table merged into it.
let currentTable = getTable tableNumber
let mergedChildren = currentTable.merged_children |> Decode.fromString(Decode.list floorplan_table_decoder)
let mergedChildren = currentTable.merged_children |> Decode.Auto.fromString<floorplan_table[]>
match mergedChildren with
| Ok listOfChildTables ->
let unmergedChild = listOfChildTables |> List.last
processUnmerge currentTable unmergedChild
| Error _ -> false
let unmergedChild = listOfChildTables |> last
processUnmerge currentTable unmergedChild |> ignore
Some (getTable currentTable.table_number, unmergedChild)
| Error _ -> None
let convertRoomListToLinks (room: floorplan_room) =
let vars = map [
"roomId", room.room_id |> string
"roomId", room.id |> string
"roomName", room.room_name
]
Theme.loadTemplateWithVars "roomButton" vars
let getReservationList (tableList: floorplan_table[]) =
let tableIds =
tableList
|> Array.map(fun table -> table.id)
|> JoinArray ","
db.connection.Query<reservation>($"""Select * From reservations Where reservation_table_id In ({tableIds})""")
|> EnumerableToArray
let newReservation name time covers =
let reservation = {
reservation_id = 0
id = 0
reservation_name = name
reservation_time = time
reservation_covers = covers
@@ -385,12 +414,12 @@ let newReservation name time covers =
value reservation
} |> db.Insert
let unReserveTable tableNumber =
let table = getTable tableNumber
DeleteReservation table.table_id
if table.status = "reserved" then
update {
table "floorplan_tables"
set {| status = "" ; reservation_id = 0 |}
} |> db.Update |> ignore
let tableList venueId =
select{
table "floorplan_tables"
innerJoin "floorplan_rooms" "id" "floorplan_tables.room_id"
}
|> db.SelectJoin<floorplan_table, floorplan_room>
|> Array.filter (fun (_, room) -> room.venue_id = venueId )
|> Array.map fst

View File

@@ -0,0 +1 @@
module GenericEntities

View File

@@ -1,6 +1,7 @@
namespace WebApplication
open Clerk
open Floorplan
open Microsoft.AspNetCore.Http
open Microsoft.AspNetCore.Mvc.RazorPages
open Microsoft.Extensions.Hosting;
@@ -23,25 +24,28 @@ module Program =
post "/authenticateClerk" (bindJson<int> (handlePostRoute AjaxController.loginWithLoginCode) )
post "/getTableData" (bindJson<int> AjaxController.getTableData)
post "/updateTableShape" (bindJson<Floorplan.floorplan_table_shape> AjaxController.updateTableShape)
post "/transformTable" (bindJson<Floorplan.floorplan_table_transform> AjaxController.transformTable)
post "/transformTable" (bindJson<Floorplan.floorplan_table> AjaxController.transformTable)
post "/createTable" (bindJson<Floorplan.floorplan_table> AjaxController.createTable)
post "/addDecoration" (bindJson<Decorations.decoration_creator> AjaxController.AddDecoration)
post "/addDecoration" (bindJson<Decorations.floorplan_decoration> AjaxController.AddDecoration)
post "/updateDecoration" (bindJson<Decorations.floorplan_decoration> AjaxController.UpdateDecoration)
post "/deleteDecoration" (bindJson<int> AjaxController.DeleteDecoration)
post "/newEmptyReservation" (bindJson<int> AjaxController.newEmptyReservation)
post "/deleteDecoration" (bindJson<Decorations.floorplan_decoration> AjaxController.DeleteDecoration)
post "/deleteTable" (bindJson<Floorplan.floorplan_table> AjaxController.deleteTable)
post "/mergeTables" (bindJson<Floorplan.floorplan_table[]> AjaxController.mergeTables)
post "/newEmptyReservation" (bindJson<reservation> AjaxController.newEmptyReservation)
post "/updateReservation" (bindJson<reservation> AjaxController.updateReservation)
post "/getReservation" (bindJson<int> (fun reservation -> json <| GetReservationById reservation) )
post "/unreserveTable" (bindJson<int> (fun tableNumber -> json <| Floorplan.unReserveTable tableNumber) )
post "/unreserveTable" (bindJson<floorplan_table> AjaxController.unreserveTable )
getf "/getRoomData/%i" AjaxController.getRoomData
getf "/getKeyboardLayout/%s" AjaxController.getKeyboardLayout
getf "/getTablesAndDecorations/%i" AjaxController.getRoomTablesAndDecorations
get "/languageVars" (json <| AjaxController.getLanguageVars)
get "/getOpenTables" (json <| Floorplan.getActiveTables Floorplan.currentVenue)
getf "/getActiveTables/%i" AjaxController.getActiveTables
getf "/tableIsOpen/%i" (fun tableNumber -> json <| Floorplan.tableIsOpen tableNumber)
getf "/transferTables/%i/%i" AjaxController.transferTable
getf "/mergeTables/%i/%i" AjaxController.mergeTables
getf "/getFloorplanData/%i" AjaxController.getFloorplanData
getf "/tableIsOpen/%i" (fun tableNumber -> json <| Floorplan.tableNumberIsOpen tableNumber)
getf "/transferTable/%i/%i" AjaxController.transferTable
getf "/unmergeTable/%i" AjaxController.unmergeTable
getf "/tableExists/%i" (fun tableNumber -> json <| Floorplan.tableExists tableNumber)
getf "/deleteTable/%i" (fun tableNumber -> json <| Floorplan.deleteTable tableNumber)
}
let pageRouter = router {
@@ -56,6 +60,7 @@ module Program =
let app = application {
use_static "wwwroot"
use_router pageRouter
}
run app

View File

@@ -3,9 +3,9 @@
open System
open DredgeFramework
open Dapper.FSharp
[<CLIMutable>]
type reservation = {
reservation_id: int
id: int
reservation_name: string
reservation_time: int
reservation_covers: int
@@ -16,13 +16,21 @@ type reservation = {
let GetReservationById (id: int) =
select {
table "reservations"
where (eq "reservation_id" id)
where (eq "id" id)
}
|> db.Select<reservation>
|> first
let updateReservation (reservation: reservation) =
update{
table "reservations"
set reservation
where(eq "id" reservation.id)
} |> db.Update |> ignore
reservation
let DeleteReservation (tableId: int) =
delete {
table "reservations"
where (eq "table_id" tableId)
where (eq "reservation_table_id" tableId)
} |> db.Delete |> ignore

View File

@@ -6,7 +6,8 @@ open Dapper.FSharp
open Clerk
open Thoth.Json.Net
type session = {session_id: string; clerk_json: string; clerk_id: int; expires: int}
[<CLIMutable>]
type session = {id: int; session_id: string; clerk_json: string; clerk_id: int; expires: int}
let deleteSession sessionId context =
delete {
@@ -25,19 +26,22 @@ let deleteSessionByClerkId clerk_id context =
let createNewSession (clerk: clerk) context =
if (getClerkByLoginCode clerk.clerk_login_code).IsSome then
deleteSessionByClerkId clerk.clerk_id context
deleteSessionByClerkId clerk.id context
let newSessionId = (Guid.NewGuid().ToString "N") + (Guid.NewGuid().ToString "N")
let newSession = { session_id = newSessionId
let newSession = {
id = 0
session_id = newSessionId
clerk_json = clerk |> jsonEncode
clerk_id = clerk.clerk_id
clerk_id = clerk.id
expires = int <| DateTimeOffset.Now.AddHours(24.0).ToUnixTimeSeconds()
}
insert {
table "sessions"
value newSession
} |> db.Insert |> ignore
}
|> db.Insert
|> ignore
Browser.setCookie "dredgepos_clerk_logged_in" newSessionId (DateTimeOffset.UtcNow.AddHours(24.0)) context
@@ -63,7 +67,7 @@ let sessionExists (sessionId: string) context =
let checkAuthentication clerk =
let existingClerk = getClerkByLoginCode clerk.clerk_login_code
if existingClerk.IsSome
&& existingClerk.Value.clerk_id = clerk.clerk_id
&& existingClerk.Value.id = clerk.id
&& existingClerk.Value.clerk_name = clerk.clerk_name
&& existingClerk.Value.clerk_login_code = clerk.clerk_login_code
then true
@@ -79,12 +83,12 @@ let getSession (sessionId: string) =
} |> db.Select<session>
match sessions |> length with
| 0 -> {session_id = ""; clerk_json = ""; clerk_id= 0; expires= 0}
| 0 -> {session_id = ""; clerk_json = ""; clerk_id= 0; expires= 0; id=0}
| _ -> sessions |> first
let getCurrentClerk context =
let cookie = getLoginCookie context
let emptyClerk = {clerk_id=0; clerk_login_code=0; clerk_usergroup=0; clerk_name=""}
let emptyClerk = {id=0; clerk_login_code=0; clerk_usergroup=0; clerk_name=""}
match cookie with
| "" ->
Browser.redirect "/login" context

Binary file not shown.

Binary file not shown.

View File

@@ -7,7 +7,6 @@
/ajax/getActiveTables/%i, GET,
/ajax/tableIsOpen/%i, GET,
/ajax/tableExists/%i, GET,
/ajax/deleteTable/%i, GET,
/ajax/authenticateClerk, POST,
/ajax/getTableData, POST,
/ajax/updateTableShape, POST,
@@ -16,7 +15,10 @@
/ajax/addDecoration, POST,
/ajax/updateDecoration, POST,
/ajax/deleteDecoration, POST,
/ajax/deleteTable, POST,
/ajax/mergeTables, POST,
/ajax/newEmptyReservation, POST,
/ajax/updateReservation, POST,
/ajax/getReservation, POST,
/ajax/unreserveTable, POST,
, NotFoundHandler,

View File

@@ -14,7 +14,7 @@
"logged_in_as":"Logged in as [1]",
"covers":"[1] Covers",
"selected_cover":"Cover [1]",
"activeTable":"Table [1]",
"active_table":"Table [1]",
"totalPrice":"Total Price: [1]",
"selectedPrice":"([1] Selected)",
"next_page":"Next Page",
@@ -60,7 +60,8 @@
"delete_table":"Delete Table",
"change_shape":"Change Shape",
"new_table_number":"New Table Number",
"transfer_table":"Transfer to New Table",
"transfer_table":"Transfer to Other Table",
"transfer_self_error":"Cannot transfer a table to itself.",
"add_decoration":"Add Decoration",
"choose_decoration":"Choose a Decoration",
"delete_decoration":"Delete Decoration",
@@ -68,9 +69,11 @@
"reserved_for":"Reserved for [1]",
"reserved":"Reserved",
"confirm_delete_reservation":"Are you sure you want to delete the reservation on table [1]?",
"confirm_reservation_name":"Who is this reservation for?",
"error_table_exists":"Table already exists in room \"[1]\"",
"error_table_exists_merged":"Table already exists in room \"[1]\", it is merged with table [2].",
"error_delete_existing_table":"Can't delete a table that's currently active.",
"error_self_merge" : "You can't merge a table with itself",
"confirm_delete_table":"Are you sure you want to delete table [1]?",
"orig_qty_header":"Original Qty",
"selected_qty_header":"Selected Qty",

Binary file not shown.

View File

@@ -1 +1 @@
4ce3c2bb1d8bbd35c1b58d110118bb059ac6cd85
6de23b71f021bbbc1f858685dc5809960956a0bb

Binary file not shown.

View File

@@ -14,7 +14,7 @@
"logged_in_as":"Logged in as [1]",
"covers":"[1] Covers",
"selected_cover":"Cover [1]",
"activeTable":"Table [1]",
"active_table":"Table [1]",
"totalPrice":"Total Price: [1]",
"selectedPrice":"([1] Selected)",
"next_page":"Next Page",
@@ -60,7 +60,8 @@
"delete_table":"Delete Table",
"change_shape":"Change Shape",
"new_table_number":"New Table Number",
"transfer_table":"Transfer to New Table",
"transfer_table":"Transfer to Other Table",
"transfer_self_error":"Cannot transfer a table to itself.",
"add_decoration":"Add Decoration",
"choose_decoration":"Choose a Decoration",
"delete_decoration":"Delete Decoration",
@@ -68,9 +69,11 @@
"reserved_for":"Reserved for [1]",
"reserved":"Reserved",
"confirm_delete_reservation":"Are you sure you want to delete the reservation on table [1]?",
"confirm_reservation_name":"Who is this reservation for?",
"error_table_exists":"Table already exists in room \"[1]\"",
"error_table_exists_merged":"Table already exists in room \"[1]\", it is merged with table [2].",
"error_delete_existing_table":"Can't delete a table that's currently active.",
"error_self_merge" : "You can't merge a table with itself",
"confirm_delete_table":"Are you sure you want to delete table [1]?",
"orig_qty_header":"Original Qty",
"selected_qty_header":"Selected Qty",

View File

@@ -1,11 +1,11 @@
let Application = {
keyboard: null,
mode: "default",
mode: [],
languageVars: {}
};
/** Parses a language variable. */
let lang = (key, replacements) => {
let finalValue = Application.languageVars[key];
let finalValue = Application.languageVars[key] || '';
if (!replacements)
return finalValue;
if (typeof replacements === 'string')
@@ -28,16 +28,19 @@ let ajax = (endpoint, data, method = 'POST', successFunction, errorFunction, bef
method: method,
data: data,
success: (response) => {
if (successFunction)
if (successFunction && response.status == 'success')
successFunction(JSON.parse(response.data));
else if (errorFunction && response.status != 'success') {
errorFunction(JSON.parse(response.data));
}
},
error: errorFunction,
error: (error) => console.log(error.statusCode),
beforeSend: beforeFunction
});
};
/*
For the flow of the app, synchronous is commonly preferred
though trying to keep it's usage as low as possible.
though trying to keep its usage as low as possible.
*/
let ajaxSync = (endpoint, data, method = 'POST') => {
let response = JSON.parse($.ajax({
@@ -56,11 +59,14 @@ let ajaxSync = (endpoint, data, method = 'POST') => {
let redirect = (url) => {
window.location.href = url;
};
let setLanguageVariables = () => {
Application.languageVars = ajaxSync('/ajax/languageVars', null, 'GET');
let setupCore = (languageVars) => {
Application.languageVars = languageVars;
const doc = $(document);
doc.on('click', '#alertNo, #alertOk', hideAlerts);
setElementVisibilityByMode();
};
// @ts-ignore
let alert = (message, title = 'Message') => {
let posAlert = (message, title = 'Message') => {
let alertBox = $('#alert');
alertBox.css('display', 'flex');
alertBox.data('value', '');
@@ -70,12 +76,11 @@ let alert = (message, title = 'Message') => {
$('#alertYes').css('display', 'none');
$('#alertNo').css('display', 'none');
};
// @ts-ignore
let confirm = (message, data, title = 'Confirm', submitFunction = (data) => { hideAlerts(); }) => {
let confirmation = (message, data, title = 'Confirm', submitFunction = (data) => { hideAlerts(); }) => {
let alert = $('#alert');
$(document).on('click', '#alert #alertYes', () => {
submitFunction(data);
hideAlerts();
submitFunction(data);
$(document).off('click', '#alert #alertYes');
});
alert.css('display', 'flex');
@@ -85,12 +90,58 @@ let confirm = (message, data, title = 'Confirm', submitFunction = (data) => { hi
$('#alertYes').css('display', 'flex');
$('#alertNo').css('display', 'flex');
};
let hideAlerts = () => {
$('#alert').hide();
let hideAlerts = () => $('#alert').hide();
let turnOnMode = (mode) => {
Application.mode.push(mode);
setElementVisibilityByMode();
};
$(() => {
let doc = $(document);
setLanguageVariables();
doc.on('click', '#alertNo, #alertOk', () => $('#alert').hide());
});
let turnOffMode = (mode) => {
Application.mode = Application.mode.filter((value) => value != mode);
setElementVisibilityByMode();
};
let toggleMode = (mode) => {
if (!isInMode(mode))
turnOnMode(mode);
else
turnOffMode(mode);
};
let clearModes = () => { Application.mode = []; };
let isInMode = (mode) => Application.mode.includes(mode);
let setElementVisibilityByMode = () => {
const mode = Application.mode;
const elements = $('[data-visible-in-mode]');
elements.each((index, elem) => {
let element = $(elem);
let visibleInModes = element.data('visible-in-mode');
let showElement = visibleInModes.every(visibleMode => {
return mode.includes(visibleMode);
});
if (element.hasClass('useVisibility')) {
if (showElement) {
element.css('visibility', 'visible');
}
else
element.css('visibility', 'hidden');
}
else
element.toggle(showElement);
});
const invisibleElements = $('[data-invisible-in-mode]');
invisibleElements.each((index, elem) => {
let element = $(elem);
let inVisibleInModes = element.data('invisible-in-mode');
let hideElement = inVisibleInModes.every(invisibleMode => {
return mode.includes(invisibleMode);
});
element.toggle(!hideElement);
});
$('[data-active-in-mode]').each((index, elem) => {
const button = $(elem);
const activeInMode = button.data('active-in-mode');
mode.includes(activeInMode)
? button.addClass('active')
: button.removeClass('active');
});
};
$(() => ajax('/ajax/languageVars', null, 'GET', setupCore, null, null));
//# sourceMappingURL=dredgepos.core.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -17,8 +17,8 @@ let showVirtualNumpad = (heading, maxlength = 4, isPassword, allowDecimals = tru
numpad.data('submitfunction', submitFunction);
numpad.data('password', isPassword);
numpad.data('allowdecimals', allowDecimals);
$(document).unbind('keyup');
$(document).keyup(e => {
$(document).off('keyup');
$(document).on('keyup', e => {
let key = e.key;
switch (key) {
case 'Backspace':
@@ -52,7 +52,6 @@ let virtualNumpadInput = (input) => {
let submitFunction = numpad.data('submitfunction');
let allowedValues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'submit', 'clear'];
let currentValue = numpad.data('value').toString();
//Test
if (allowDecimals)
allowedValues.push('.', ',');
let validInput = allowedValues.includes(input);
@@ -91,11 +90,12 @@ let setupVirtualNumpad = () => {
hideVirtualNumpad();
});
};
let setupVirtualKeyboard = () => {
let setupVirtualKeyboard = (keyboardLayouts) => {
Application.keyboard = {
capsLock: false,
shift: false,
layout: 'default'
layouts: keyboardLayouts,
currentLayout: 'default',
};
$(document).on('click', '.virtualKeyboardButton', e => {
virtualKeyboardInput($(e.target).data('value'));
@@ -138,7 +138,7 @@ let virtualKeyboardInput = (input) => {
case 'submit':
hideVirtualKeyboard();
let submitFunction = keyboard.data('submitfunction');
submitFunction();
submitFunction(inputBox.text());
break;
case 'shift':
if (Application.keyboard.capsLock)
@@ -174,16 +174,17 @@ let virtualKeyboardInput = (input) => {
}
};
let setKeyboardLayout = (layout, modifier = '') => {
let keyboardLayout = ajaxSync('/languages/english/keyboardLayout.json', null, 'get');
if (modifier != '')
modifier = `_${modifier}`;
Application.keyboard.currentLayout = layout;
let layoutToLoad = Application.keyboard.layouts[layout];
$('.virtualKeyboardRow').each((index, row) => {
/*
We start at 1 instead of 0. Makes it easier for non-programmers
and translators making their own language packs
*/
index = index + 1;
let currentRow = keyboardLayout[layout]["row" + index + modifier];
let currentRow = layoutToLoad[`row${index}${modifier}`];
$(row).children('a').each((keyIndex, button) => {
let key = $(button);
let keyValue = currentRow[keyIndex];
@@ -211,6 +212,6 @@ let setKeyboardLayout = (layout, modifier = '') => {
};
$(() => {
setupVirtualNumpad();
setupVirtualKeyboard();
ajax('/ajax/getKeyboardLayout/english', null, 'get', setupVirtualKeyboard, null, null);
});
//# sourceMappingURL=keyboards.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,13 +1,13 @@
let Application : ApplicationState = {
keyboard : null,
mode: "default",
mode: [],
languageVars: {}
}
/** Parses a language variable. */
let lang = (key: string, replacements?: string[] | string) => {
let finalValue = Application.languageVars[key]
let finalValue = Application.languageVars[key] || ''
if(!replacements) return finalValue
if(typeof replacements === 'string') replacements = [replacements]
@@ -26,17 +26,20 @@
}
/** Call an Ajax function asynchronously */
let ajax = (endpoint : string, data: any, method = 'POST', successFunction : Function , errorFunction : JQuery.Ajax.ErrorCallback<any>, beforeFunction: any) => {
let ajax = (endpoint : string, data: any, method = 'POST', successFunction : Function , errorFunction : Function, beforeFunction: any) => {
data = (data == null) ? data : JSON.stringify(data)
return $.ajax({
url: endpoint,
method: method,
data: data,
success: (response) => {
if(successFunction)
success: (response: ajaxResult) => {
if(successFunction && response.status == 'success')
successFunction(JSON.parse(response.data))
else if (errorFunction && response.status != 'success'){
errorFunction(JSON.parse(response.data))
}
},
error: errorFunction,
error: (error) => console.log(error.statusCode),
beforeSend: beforeFunction
})
}
@@ -44,7 +47,7 @@
/*
For the flow of the app, synchronous is commonly preferred
though trying to keep it's usage as low as possible.
though trying to keep its usage as low as possible.
*/
let ajaxSync = (endpoint : string, data?: any, method = 'POST') => {
let response = JSON.parse(
@@ -69,12 +72,17 @@
}
let setLanguageVariables = () => {
Application.languageVars = ajaxSync('/ajax/languageVars', null, 'GET')
let setupCore = (languageVars: Record<string, string>) => {
Application.languageVars = languageVars
const doc = $(document)
doc.on('click', '#alertNo, #alertOk', hideAlerts)
setElementVisibilityByMode()
}
// @ts-ignore
let alert = (message: string, title='Message') => {
let posAlert = (message: string, title='Message') => {
let alertBox = $('#alert')
alertBox.css('display', 'flex');
alertBox.data('value', '');
@@ -86,13 +94,12 @@
$('#alertNo').css('display', 'none');
}
// @ts-ignore
let confirm = (message: string, data: any, title='Confirm', submitFunction = (data: any) => {hideAlerts()}) => {
let confirmation = (message: string, data: any, title='Confirm', submitFunction = (data: any) => {hideAlerts()}) => {
let alert = $('#alert')
$(document).on('click', '#alert #alertYes', () => {
submitFunction(data)
hideAlerts()
submitFunction(data)
$(document).off('click', '#alert #alertYes')
})
@@ -106,13 +113,69 @@
}
let hideAlerts = () => {
$('#alert').hide()
let hideAlerts = () => $('#alert').hide()
let turnOnMode = (mode : PosMode) => {
Application.mode.push(mode)
setElementVisibilityByMode()
}
$( () => {
let doc = $(document)
setLanguageVariables()
let turnOffMode = (mode : PosMode) => {
Application.mode = Application.mode.filter((value) => value != mode)
setElementVisibilityByMode()
doc.on('click', '#alertNo, #alertOk', () => $('#alert').hide())
})
}
let toggleMode = (mode: PosMode) => {
if(!isInMode(mode))
turnOnMode(mode)
else
turnOffMode(mode)
}
let clearModes = () => {Application.mode = []}
let isInMode = (mode: PosMode) => Application.mode.includes(mode)
let setElementVisibilityByMode = () => {
const mode = Application.mode
const elements = $('[data-visible-in-mode]')
elements.each((index, elem) => {
let element = $(elem)
let visibleInModes : PosModes = element.data('visible-in-mode')
let showElement = visibleInModes.every( visibleMode => {
return mode.includes(visibleMode)
});
if(element.hasClass('useVisibility')){
if(showElement) {
element.css('visibility', 'visible')
} else element.css('visibility', 'hidden')
} else element.toggle(showElement)
})
const invisibleElements = $('[data-invisible-in-mode]')
invisibleElements.each((index, elem) => {
let element = $(elem)
let inVisibleInModes: PosModes = element.data('invisible-in-mode')
let hideElement = inVisibleInModes.every(invisibleMode => {
return mode.includes(invisibleMode)
})
element.toggle(!hideElement)
})
$('[data-active-in-mode]').each((index, elem) =>{
const button = $(elem)
const activeInMode : PosMode = button.data('active-in-mode')
mode.includes(activeInMode)
? button.addClass('active')
: button.removeClass('active')
})
}
$( () => ajax('/ajax/languageVars', null, 'GET', setupCore, null, null))

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,9 @@
let showVirtualNumpad = (heading: string, maxlength = 4, isPassword: boolean, allowDecimals = true, allowClose = true, submitFunction: Function) => {
type KeyboardRowName = `row${number}${"" | "_"}${string}`;
interface VirtualKeyboard {
[layoutName: string]: Partial<Record<KeyboardRowName, string[]>>;
}
let showVirtualNumpad = (heading: string, maxlength = 4, isPassword: boolean, allowDecimals = true, allowClose = true, submitFunction: Function) => {
let numpad = $('#virtualNumpad');
let inputBox = $('#virtualNumpadInput')
let closeKeyboardButton = $('.closeKeyboards')
@@ -23,10 +28,9 @@
numpad.data('password', isPassword);
numpad.data('allowdecimals', allowDecimals);
$(document).unbind('keyup');
$(document).keyup(e => {
$(document).off('keyup');
$(document).on('keyup', e => {
let key = e.key;
switch (key) {
case 'Backspace':
case 'Delete':
@@ -64,7 +68,7 @@
let submitFunction = numpad.data('submitfunction')
let allowedValues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'submit', 'clear']
let currentValue = numpad.data('value').toString()
//Test
if (allowDecimals)
allowedValues.push('.', ',')
@@ -109,11 +113,12 @@
});
}
let setupVirtualKeyboard = () => {
let setupVirtualKeyboard = (keyboardLayouts: VirtualKeyboard) => {
Application.keyboard = {
capsLock: false,
shift: false,
layout: 'default'
layouts: keyboardLayouts,
currentLayout: 'default',
}
$(document).on('click', '.virtualKeyboardButton', e => {
@@ -123,7 +128,7 @@
setKeyboardLayout('default')
}
let showVirtualKeyboard = (heading: string, maxlength = 32, isPassword = false, submitFunction = () => {
let showVirtualKeyboard = (heading: string, maxlength = 32, isPassword = false, submitFunction :Function = () => {
hideVirtualKeyboard()
}) => {
let keyboard = $('#virtualKeyboard')
@@ -166,7 +171,7 @@
case 'submit':
hideVirtualKeyboard();
let submitFunction = keyboard.data('submitfunction')
submitFunction();
submitFunction(inputBox.text());
break;
case 'shift':
if (Application.keyboard.capsLock) break;
@@ -206,8 +211,10 @@
}
let setKeyboardLayout = (layout: string, modifier = '') => {
let keyboardLayout = ajaxSync('/languages/english/keyboardLayout.json', null, 'get')
if (modifier != '') modifier = `_${modifier}`
Application.keyboard.currentLayout = layout
let layoutToLoad = Application.keyboard.layouts[layout]
$('.virtualKeyboardRow').each((index, row) => {
/*
@@ -215,7 +222,7 @@
and translators making their own language packs
*/
index = index + 1;
let currentRow: Record<string, string> = keyboardLayout[layout]["row" + index + modifier]
let currentRow = layoutToLoad[`row${index}${modifier}`]
$(row).children('a').each((keyIndex, button) => {
let key = $(button);
@@ -252,5 +259,5 @@
$(() => {
setupVirtualNumpad()
setupVirtualKeyboard();
ajax('/ajax/getKeyboardLayout/english', null, 'get',setupVirtualKeyboard, null, null)
})

View File

@@ -0,0 +1 @@

View File

@@ -1,4 +1,5 @@
type PosMode = "edit" | "void" | "transfer" | "default"
type PosMode = "edit" | "void" | "transfer" | "default" | "tableSelected" | "decorationSelected" | "activeTableSelected" | "merge" | "reservedTableSelected"
type PosModes = PosMode[]
interface ajaxResult {
status: string
@@ -7,11 +8,10 @@ interface ajaxResult {
interface ApplicationState {
keyboard: keyboard
mode: PosMode
mode: PosModes
languageVars: Record<any, string>
}
interface table {
table_number: number,
room_id: number
@@ -25,20 +25,41 @@ interface table {
rotation: number
merged_children: string
previous_state: string
status: string
table_id: number
status: number
id: number
}
interface decoration {
id: number
decoration_room: number
decoration_pos_x: number
decoration_pos_y: number
decoration_rotation: number
decoration_width: number
decoration_height: number
decoration_image: string
}
interface room {
room_id: number
id: number
room_name: string
background_image: string
venue_id: number
}
interface reservation {
id: number,
reservation_name: string,
reservation_time: number,
reservation_covers: number,
reservation_created_at: number,
reservation_table_id: number,
}
interface keyboard {
capsLock: boolean
shift: boolean
layout: string
layouts: VirtualKeyboard
currentLayout: string
}

View File

@@ -553,14 +553,14 @@ a.logOut{
.floorplanControls,
.mergeControls{
visibility:hidden;
width:100%;
flex-basis:33%;
display:flex;
flex-direction:column;
}
.editControls a{
.editControls > a,
.editControls .posHeader{
height:100%;
display:flex;
flex-wrap:wrap;
@@ -568,12 +568,23 @@ a.logOut{
align-items:center;
justify-content:center;
text-align:center;
padding:0.5em;
}
.editControls .posHeader{
flex-direction:column;
}
.posHeader.currentTable > * {
width: 100%;
flex:1;
align-items: center;
display: flex;
justify-content: center;
}
.posHeader.currentTable b {align-items: flex-end}
.posHeader.currentTable small {align-items: flex-start}
.floorplanControls a,
.mergeControls a{
display:flex;

View File

@@ -27,13 +27,17 @@
<div id="tableMap"></div>
</div>
<div id="centerBottomRow">
<div class="editControls">
<a class="posHeader currentTable"></a>
<a onclick="loadScreen('orderScreen', 'table='+selectedTableNumber)" class="posButton"><!--[lang:order_table]--></a>
<a class="posButton reserveTableButton"><!--[lang:reserve_table]--></a>
<a onclick="loadScreen('paymentSplitter', 'table='+selectedTableNumber)" class="posButton payTableButton"><!--[lang:pay_table]--></a>
<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"><!--[lang:order_table]--></a>
<a class="posButton reserveTableButton" data-invisible-in-mode='["reservedTableSelected"]'><!--[lang:reserve_table]--></a>
<a class="posButton unreserveTableButton" data-visible-in-mode='["reservedTableSelected"]'><!--[lang:unreserve_table]--></a>
<a class="posButton payTableButton"><!--[lang:pay_table]--></a>
<a class="posButton viewTableButton"><!--[lang:view_table]--></a>
</div>
</div>
</div>
@@ -43,17 +47,17 @@
</div>
<div class="middleCell">
<a class="posButton editModeButton"><!--[lang:edit_floorplan]--></a>
<div class="floorplanControls">
<a class="posButton addTableButton"><!--[lang:add_table]--></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"><!--[lang:delete_decoration]--></a>
<a class="posButton deleteTableButton"><!--[lang:delete_table]--></a>
<a class="posButton changeShapeButton"><!--[lang:change_shape]--></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">
<a onclick="mergeModeOn()" class="posButton mergeButton"><!--[lang:merge_table]--></a>
<a onclick="unmergeTable()" class="posButton unmergeButton"><!--[lang:unmerge_table]--></a>
<a class="transferTableButton posButton"><!--[lang:transfer_table]--></a>
<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">
@@ -70,14 +74,5 @@
</div>
<div id="decoratorContent"><!--[var:decorator]--></div>
</div>
<script type="text/javascript">
var roomToLoad = 1;
var width = 1152
var height = 850
$(document).ready( function () {
setupTableMap();
} );
</script>
</body>
</html>