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

View File

@@ -1,9 +1,12 @@
module AjaxController module AjaxController
open DredgeFramework open DredgeFramework
open Floorplan
open Microsoft.AspNetCore.Http open Microsoft.AspNetCore.Http
open Reservations
open language open language
open Giraffe open Giraffe
open Dapper.FSharp
let loginWithLoginCode (context: HttpContext) (login_code: int) = let loginWithLoginCode (context: HttpContext) (login_code: int) =
if Session.clerkLogin login_code context then ajaxSuccess "success" 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 getRoomData roomId = Floorplan.getRoom roomId |> ajaxSuccess |> json
let mergeTables (parent, child) = let mergeTables (tables: floorplan_table[]) =
let status = let status =
if Floorplan.mergeTables parent child then "success" if mergeTables tables.[0].table_number tables.[1].table_number then
else "fail" let outputTables = map [
"parent", tables.[0];
map [ "child", tables.[1];
"status", status "merged", getTable tables.[0].table_number;
"data" , parent |> Floorplan.getTable |> jsonEncode
] ]
|> json ajaxSuccess outputTables
else ajaxFail "Could Not Merge Tables"
status |> json
let unmergeTable tableNumber = let unmergeTable tableNumber =
let status = let unmerged = Floorplan.unmergeTable tableNumber
if Floorplan.unmergeTable tableNumber then "success" let unmergedTables =
else "fail" match unmerged with
| Some (parent, child) ->
map["parent", parent; "child", child] |> ajaxSuccess
| None -> ajaxFail "Could not Unmerge Table"
map [ unmergedTables |> json
"status", status
"data" , "[true]"
] 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 |> json
let getKeyboardLayout (language: string) =
let layout = $"""wwwroot/languages/{language}/keyboardLayout.json""" |> GetFileContents
map [
"status", "success"
"data", layout
] |> json
let getRoomTablesAndDecorations roomId = let getRoomTablesAndDecorations roomId =
let tables = Floorplan.tablesInRoom roomId let tables = Floorplan.tablesInRoom roomId
let decorations = Decorations.decorationsInRoom roomId let decorations = Decorations.decorationsInRoom roomId
@@ -53,50 +78,70 @@ let updateTableShape (table: Floorplan.floorplan_table_shape) =
Floorplan.updateTableShape table |> ignore Floorplan.updateTableShape table |> ignore
getTableData table.table_number getTableData table.table_number
let transformTable (table: Floorplan.floorplan_table_transform) = let transformTable (table: Floorplan.floorplan_table) =
Floorplan.updateTablePosition table |> ignore Floorplan.updateTablePosition table |> ignore
getTableData table.table_number getTableData table.table_number
let createTable (tableData) = let createTable (tableData: floorplan_table) =
let newTableCreated = Floorplan.addNewTable tableData
let result = let result =
if newTableCreated then Floorplan.getTable tableData.table_number |> jsonEncode |> ajaxSuccess if tableExists tableData.table_number = "False" then
else Floorplan.tableExists tableData.table_number |> jsonEncode |> ajaxFail 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) = let transferTable (origin, destination) =
Floorplan.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 image = "wwwroot/images/decorations/" + data.decoration_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 : Decorations.floorplan_decoration = { let decoration : Decorations.floorplan_decoration = {
decoration_id = 0 id = 0
decoration_height = (200m / aspectRatio) |> int decoration_height = (200m / aspectRatio) |> int
decoration_width = 200 decoration_width = 200
decoration_rotation = 0 decoration_rotation = 0
decoration_image = data.decoration_image decoration_image = data.decoration_image
decoration_pos_x = data.basis/2 decoration_pos_x = data.decoration_pos_x
decoration_pos_y = data.basis/2 decoration_pos_y = data.decoration_pos_y
decoration_room = data.decoration_room decoration_room = data.decoration_room
} }
Decorations.CreateDecoration decoration |> ignore Decorations.CreateDecoration decoration |> ajaxSuccess |> json
ajaxSuccess "true" |> json
let UpdateDecoration data = let UpdateDecoration data =
Decorations.UpdateDecoration data |> ignore Decorations.UpdateDecoration data |> ignore
ajaxSuccess "true" |> json ajaxSuccess "true" |> json
let DeleteDecoration id = let DeleteDecoration id = ajaxSuccess (Decorations.DeleteDecoration id) |> json
Decorations.DeleteDecorationById id |> ignore
ajaxSuccess "true" |> json
let newEmptyReservation tableNumber = let newEmptyReservation (reservation: reservation) =
Floorplan.createEmptyReservation tableNumber 2 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 = "" 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> = let clerk_decoder : Decoder<clerk> =
Decode.object Decode.object
(fun get -> (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_name = get.Required.Field "clerk_name" Decode.string
clerk_login_code = get.Required.Field "clerk_login_code" Decode.int clerk_login_code = get.Required.Field "clerk_login_code" Decode.int
clerk_usergroup = get.Required.Field "clerk_usergroup" Decode.int clerk_usergroup = get.Required.Field "clerk_usergroup" Decode.int

View File

@@ -1,5 +1,7 @@
module db module db
open Dapper
open Dapper.FSharp
open Dapper.FSharp.MySQL open Dapper.FSharp.MySQL
open MySql.Data.MySqlClient open MySql.Data.MySqlClient
open DredgeFramework open DredgeFramework
@@ -24,6 +26,16 @@ let Insert<'a> asyncQuery =
|> connection.InsertAsync<'a> |> connection.InsertAsync<'a>
|> RunSynchronously |> 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 = let Update<'a> asyncQuery =
asyncQuery asyncQuery
|> connection.UpdateAsync<'a> |> connection.UpdateAsync<'a>

View File

@@ -6,10 +6,11 @@ open System.Text.RegularExpressions
open DredgeFramework open DredgeFramework
open Dapper open Dapper
open Dapper.FSharp open Dapper.FSharp
open Floorplan
[<CLIMutable>] [<CLIMutable>]
type floorplan_decoration = { type floorplan_decoration = {
decoration_id: int id: int
decoration_room: int decoration_room: int
decoration_pos_x: int decoration_pos_x: int
decoration_pos_y: int decoration_pos_y: int
@@ -19,12 +20,14 @@ type floorplan_decoration = {
decoration_image: string decoration_image: string
} }
type decoration_creator = { let decorationList venue =
decoration_room: int select {
decoration_image: string table "floorplan_decorations"
basis: int 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) = let decorationsInRoom (roomId: int) =
select { select {
@@ -43,8 +46,6 @@ let getImageName (image: string, path: string) =
imageName, path imageName, path
let isImageFile (fileName: string) = Regex.IsMatch(fileName |> ToLowerCase, @"^.+\.(jpg|jpeg|png|gif)$") let isImageFile (fileName: string) = Regex.IsMatch(fileName |> ToLowerCase, @"^.+\.(jpg|jpeg|png|gif)$")
let getImageHTML (imageName: string, imageUrl: string) = let getImageHTML (imageName: string, imageUrl: string) =
@@ -77,20 +78,21 @@ let CreateDecoration (decoration: floorplan_decoration) =
insert { insert {
table "floorplan_decorations" table "floorplan_decorations"
value decoration value decoration
} |> db.Insert }
|> db.InsertOutput
|> first
let UpdateDecoration (decoration: floorplan_decoration) = let UpdateDecoration (decoration: floorplan_decoration) =
let imageFile = GetFileName decoration.decoration_image
let updatedDecoration = {decoration with decoration_image = imageFile}
update { update {
table "floorplan_decorations" table "floorplan_decorations"
set updatedDecoration set decoration
where (eq "decoration_id" decoration.decoration_id ) where (eq "id" decoration.id )
} |> db.Update } |> db.Update
let DeleteDecorationById (id: int) = let DeleteDecoration (decoration: floorplan_decoration) =
delete { delete {
table "floorplan_decorations" table "floorplan_decorations"
where (eq "decoration_id" id) where (eq "id" decoration.id)
} |> db.Delete } |> 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 map list = list |> Map.ofList
let JoinArray (char: string) (array: string[]) = String.Join(char, array) let JoinArray (char: string) (array: 'a[]) = String.Join(char, array)
let first (array: 'a[]) = array.[0]
let StringReplace (search:string) (replace:string) (string:string) = (search, replace) |> string.Replace 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 GetFileName (file: string) = Path.GetFileName file
let length (variable: 'T[]) = variable.Length 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 let removeFalseValues (variable: bool[]) = variable |> Array.filter id
@@ -67,14 +68,15 @@ let RunSynchronously task =
|> Async.AwaitTask |> Async.AwaitTask
|> Async.RunSynchronously |> Async.RunSynchronously
let AppendToArray (element: 'T) (array : 'T[]) = Array.append [|element|] array
let ToLowerCase (string: string) = string.ToLower() let ToLowerCase (string: string) = string.ToLower()
let ToUpperCase (string: string) = string.ToUpper() let ToUpperCase (string: string) = string.ToUpper()
let ToTitleCase (string: string) = CultureInfo.CurrentCulture.TextInfo.ToTitleCase <| string let ToTitleCase (string: string) = CultureInfo.CurrentCulture.TextInfo.ToTitleCase <| string
let recordToMap (record: 'T) = let recordToMap (record: 'T) =
seq { seq {
for prop in FSharpType.GetRecordFields(typeof<'T>) -> for prop in FSharpType.GetRecordFields(typeof<'T>) -> prop.Name, prop.GetValue(record) |> string
prop.Name, prop.GetValue(record) |> string
} }
|> Map.ofSeq |> Map.ofSeq

View File

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

View File

@@ -38,13 +38,13 @@ type floorplan_table = {
rotation: int rotation: int
merged_children: string merged_children: string
previous_state: string previous_state: string
status: string status: int
table_id: int id: int
} }
[<CLIMutable>] [<CLIMutable>]
type floorplan_room = { type floorplan_room = {
room_id: int id: int
room_name: string room_name: string
background_image: string background_image: string
venue_id: int venue_id: int
@@ -66,8 +66,8 @@ let floorplan_table_decoder : Decoder<floorplan_table> =
rotation = get.Required.Field "rotation" Decode.int rotation = get.Required.Field "rotation" Decode.int
merged_children = get.Required.Field "merged_children" Decode.string merged_children = get.Required.Field "merged_children" Decode.string
previous_state = get.Required.Field "previous_state" Decode.string previous_state = get.Required.Field "previous_state" Decode.string
status = get.Required.Field "status" Decode.string status = get.Required.Field "status" Decode.int
table_id = get.Required.Field "table_id" Decode.int id = get.Required.Field "id" Decode.int
}) })
@@ -78,10 +78,12 @@ let getTableFile (tableNumber: int) =
let tableNumberString = tableNumber |> string let tableNumberString = tableNumber |> string
activeTablePath + "table" + tableNumberString + ".table" activeTablePath + "table" + tableNumberString + ".table"
let tableIsOpen (tableNumber: int) = let tableNumberIsOpen (tableNumber: int) =
let tableFile = getTableFile tableNumber let tableFile = getTableFile tableNumber
File.Exists tableFile 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 let fileNameToTableNumber (fileName: string) = //Takes a file name for a floorplan table and returns the table number
if fileName.Contains ".table" then if fileName.Contains ".table" then
let fileName = (fileName.Split ".").[0] 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> |> db.Select<floorplan_table>
let getActiveTables (venueId: int) = let getActiveTables (venueId: int) =
select{ select{
table "floorplan_tables" table "floorplan_tables"
where (eq "venue_id" venueId) where (eq "venue_id" venueId)
} }
|> db.Select |> db.Select
|> Array.map getTableNumber
|> Array.filter tableIsOpen |> Array.filter tableIsOpen
|> Array.map (fun table -> table.table_number)
let openNewTable tableNumber = //Create a new table file pre-populated with skeleton data let openNewTable tableNumber = //Create a new table file pre-populated with skeleton data
let tableFile = getTableFile tableNumber let tableFile = getTableFile tableNumber
@@ -128,10 +129,10 @@ let transferTable origin destination = //Transfers a table from one to another
let originFile = getTableFile origin let originFile = getTableFile origin
let destinationFile = getTableFile destination let destinationFile = getTableFile destination
if tableIsOpen origin then if tableNumberIsOpen origin then
(* If the destination is not an already open table, (* If the destination is not an already open table,
then we simply have to rename the origin to destination *) 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 content = File.ReadAllText originFile
let newContent = content.Replace($"number=\"{origin|>string}\">", $"number=\"{destination|>string}\">") let newContent = content.Replace($"number=\"{origin|>string}\">", $"number=\"{destination|>string}\">")
File.WriteAllText(originFile, newContent) File.WriteAllText(originFile, newContent)
@@ -159,10 +160,18 @@ let getTable (tableNumber : int) =
|> db.Select<floorplan_table> |> db.Select<floorplan_table>
|> first |> first
let getTableById (id : int) =
select {
table "floorplan_tables"
where (eq "id" id)
}
|> db.Select<floorplan_table>
|> first
let getRoom (roomId: int) = let getRoom (roomId: int) =
select { select {
table "floorplan_rooms" table "floorplan_rooms"
where (eq "room_id" roomId) where (eq "id" roomId)
} |> db.Select<floorplan_room> |> first } |> db.Select<floorplan_room> |> first
let getRoomList (venueId: int) = let getRoomList (venueId: int) =
@@ -172,6 +181,7 @@ let getRoomList (venueId: int) =
} |> db.Select<floorplan_room> } |> db.Select<floorplan_room>
let updateFloorplanTable (tableNumber:int) (column: string) value = 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 sql = "Update floorplan_tables Set @column = @value Where table_number = @tableNumber"
let parameters = [("column", box column); ("value", box value); ("tableNumber", box tableNumber)] let parameters = [("column", box column); ("value", box value); ("tableNumber", box tableNumber)]
db.connection.Execute(sql, parameters) |> ignore 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) where (eq "table_number" floorplanTable.table_number + eq "venue_id" currentVenue)
} |> db.Update } |> db.Update
let updateTablePosition (floorplanTable: floorplan_table_transform) =
let updateTablePosition (floorplanTable: floorplan_table) =
update { update {
table "floorplan_tables" table "floorplan_tables"
set floorplanTable set floorplanTable
where (eq "table_number" floorplanTable.table_number + eq "venue_id" currentVenue) where (eq "table_number" floorplanTable.table_number + eq "venue_id" currentVenue)
} |> db.Update } |> db.Update
let createEmptyReservation tableNumber covers = let createEmptyReservation (reservation: reservation) =
let table = getTable tableNumber
let status = if table.status = "" then "reserved" else table.status
//let res = newReservation "" 0 covers
update { update {
table "floorplan_tables" table "floorplan_tables"
set {| status = status |} set {| status = 2 |}
where(eq "table_number" tableNumber) where(eq "id" reservation.reservation_table_id)
} |> db.Update |> ignore } |> db.Update |> ignore
insert{
table "reservations"
value reservation
} |> db.InsertOutput |> first
let getChildTables tableNumber = let getChildTables tableNumber =
@@ -217,7 +228,7 @@ let matchTable (tableNumberToMatch: int) (floorplanTableToCheck: floorplan_table
let findChildTable (childTable: int) (parentTable: floorplan_table) = let findChildTable (childTable: int) (parentTable: floorplan_table) =
let json = parentTable.merged_children 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 = let matchedTables =
match childTables with match childTables with
@@ -262,16 +273,24 @@ let tableExists (tableNumber: int) =
language.getAndReplace "error_table_exists" [room.room_name] language.getAndReplace "error_table_exists" [room.room_name]
let addNewTable newTable = let addNewTableWithoutOutput (newTable: floorplan_table) =
if tableExists newTable.table_number = "False" then
insert{ insert{
table "floorplan_tables" table "floorplan_tables"
value newTable value newTable
} |> db.Insert |> ignore }
true |> db.Insert
else false
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 { delete {
table "floorplan_tables" table "floorplan_tables"
where (eq "table_number" tableNumber + eq "venue_id" currentVenue) 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) where(eq "table_number" parentTable.table_number + eq "venue_id" currentVenue)
} |> db.Update |> ignore } |> db.Update |> ignore
addNewTable childTable |> ignore addNewTableWithoutOutput childTable |> ignore
true true
let processUnmerge originalTable unmergedChild = 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 unmergeTable tableNumber = //Separates a merged table into itself and the last table merged into it.
let currentTable = getTable tableNumber 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 match mergedChildren with
| Ok listOfChildTables -> | Ok listOfChildTables ->
let unmergedChild = listOfChildTables |> List.last let unmergedChild = listOfChildTables |> last
processUnmerge currentTable unmergedChild processUnmerge currentTable unmergedChild |> ignore
| Error _ -> false Some (getTable currentTable.table_number, unmergedChild)
| Error _ -> None
let convertRoomListToLinks (room: floorplan_room) = let convertRoomListToLinks (room: floorplan_room) =
let vars = map [ let vars = map [
"roomId", room.room_id |> string "roomId", room.id |> string
"roomName", room.room_name "roomName", room.room_name
] ]
Theme.loadTemplateWithVars "roomButton" vars 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 newReservation name time covers =
let reservation = { let reservation = {
reservation_id = 0 id = 0
reservation_name = name reservation_name = name
reservation_time = time reservation_time = time
reservation_covers = covers reservation_covers = covers
@@ -385,12 +414,12 @@ let newReservation name time covers =
value reservation value reservation
} |> db.Insert } |> 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 namespace WebApplication
open Clerk open Clerk
open Floorplan
open Microsoft.AspNetCore.Http open Microsoft.AspNetCore.Http
open Microsoft.AspNetCore.Mvc.RazorPages open Microsoft.AspNetCore.Mvc.RazorPages
open Microsoft.Extensions.Hosting; open Microsoft.Extensions.Hosting;
@@ -23,25 +24,28 @@ module Program =
post "/authenticateClerk" (bindJson<int> (handlePostRoute AjaxController.loginWithLoginCode) ) post "/authenticateClerk" (bindJson<int> (handlePostRoute AjaxController.loginWithLoginCode) )
post "/getTableData" (bindJson<int> AjaxController.getTableData) post "/getTableData" (bindJson<int> AjaxController.getTableData)
post "/updateTableShape" (bindJson<Floorplan.floorplan_table_shape> AjaxController.updateTableShape) 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 "/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 "/updateDecoration" (bindJson<Decorations.floorplan_decoration> AjaxController.UpdateDecoration)
post "/deleteDecoration" (bindJson<int> AjaxController.DeleteDecoration) post "/deleteDecoration" (bindJson<Decorations.floorplan_decoration> AjaxController.DeleteDecoration)
post "/newEmptyReservation" (bindJson<int> AjaxController.newEmptyReservation) 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 "/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 "/getRoomData/%i" AjaxController.getRoomData
getf "/getKeyboardLayout/%s" AjaxController.getKeyboardLayout
getf "/getTablesAndDecorations/%i" AjaxController.getRoomTablesAndDecorations getf "/getTablesAndDecorations/%i" AjaxController.getRoomTablesAndDecorations
get "/languageVars" (json <| AjaxController.getLanguageVars) get "/languageVars" (json <| AjaxController.getLanguageVars)
get "/getOpenTables" (json <| Floorplan.getActiveTables Floorplan.currentVenue) get "/getOpenTables" (json <| Floorplan.getActiveTables Floorplan.currentVenue)
getf "/getActiveTables/%i" AjaxController.getActiveTables getf "/getActiveTables/%i" AjaxController.getActiveTables
getf "/tableIsOpen/%i" (fun tableNumber -> json <| Floorplan.tableIsOpen tableNumber) getf "/getFloorplanData/%i" AjaxController.getFloorplanData
getf "/transferTables/%i/%i" AjaxController.transferTable getf "/tableIsOpen/%i" (fun tableNumber -> json <| Floorplan.tableNumberIsOpen tableNumber)
getf "/mergeTables/%i/%i" AjaxController.mergeTables getf "/transferTable/%i/%i" AjaxController.transferTable
getf "/unmergeTable/%i" AjaxController.unmergeTable getf "/unmergeTable/%i" AjaxController.unmergeTable
getf "/tableExists/%i" (fun tableNumber -> json <| Floorplan.tableExists tableNumber) getf "/tableExists/%i" (fun tableNumber -> json <| Floorplan.tableExists tableNumber)
getf "/deleteTable/%i" (fun tableNumber -> json <| Floorplan.deleteTable tableNumber)
} }
let pageRouter = router { let pageRouter = router {
@@ -56,6 +60,7 @@ module Program =
let app = application { let app = application {
use_static "wwwroot" use_static "wwwroot"
use_router pageRouter use_router pageRouter
} }
run app run app

View File

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

View File

@@ -6,7 +6,8 @@ open Dapper.FSharp
open Clerk open Clerk
open Thoth.Json.Net 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 = let deleteSession sessionId context =
delete { delete {
@@ -25,19 +26,22 @@ let deleteSessionByClerkId clerk_id context =
let createNewSession (clerk: clerk) context = let createNewSession (clerk: clerk) context =
if (getClerkByLoginCode clerk.clerk_login_code).IsSome then 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 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_json = clerk |> jsonEncode
clerk_id = clerk.clerk_id clerk_id = clerk.id
expires = int <| DateTimeOffset.Now.AddHours(24.0).ToUnixTimeSeconds() expires = int <| DateTimeOffset.Now.AddHours(24.0).ToUnixTimeSeconds()
} }
insert { insert {
table "sessions" table "sessions"
value newSession value newSession
} |> db.Insert |> ignore }
|> db.Insert
|> 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
@@ -63,7 +67,7 @@ let sessionExists (sessionId: string) context =
let checkAuthentication clerk = let checkAuthentication clerk =
let existingClerk = getClerkByLoginCode clerk.clerk_login_code let existingClerk = getClerkByLoginCode clerk.clerk_login_code
if existingClerk.IsSome 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_name = clerk.clerk_name
&& existingClerk.Value.clerk_login_code = clerk.clerk_login_code && existingClerk.Value.clerk_login_code = clerk.clerk_login_code
then true then true
@@ -79,12 +83,12 @@ let getSession (sessionId: string) =
} |> db.Select<session> } |> db.Select<session>
match sessions |> length with 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 | _ -> sessions |> first
let getCurrentClerk context = let getCurrentClerk context =
let cookie = getLoginCookie 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 match cookie with
| "" -> | "" ->
Browser.redirect "/login" context Browser.redirect "/login" context

Binary file not shown.

Binary file not shown.

View File

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

View File

@@ -14,7 +14,7 @@
"logged_in_as":"Logged in as [1]", "logged_in_as":"Logged in as [1]",
"covers":"[1] Covers", "covers":"[1] Covers",
"selected_cover":"Cover [1]", "selected_cover":"Cover [1]",
"activeTable":"Table [1]", "active_table":"Table [1]",
"totalPrice":"Total Price: [1]", "totalPrice":"Total Price: [1]",
"selectedPrice":"([1] Selected)", "selectedPrice":"([1] Selected)",
"next_page":"Next Page", "next_page":"Next Page",
@@ -60,7 +60,8 @@
"delete_table":"Delete Table", "delete_table":"Delete Table",
"change_shape":"Change Shape", "change_shape":"Change Shape",
"new_table_number":"New Table Number", "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", "add_decoration":"Add Decoration",
"choose_decoration":"Choose a Decoration", "choose_decoration":"Choose a Decoration",
"delete_decoration":"Delete Decoration", "delete_decoration":"Delete Decoration",
@@ -68,9 +69,11 @@
"reserved_for":"Reserved for [1]", "reserved_for":"Reserved for [1]",
"reserved":"Reserved", "reserved":"Reserved",
"confirm_delete_reservation":"Are you sure you want to delete the reservation on table [1]?", "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":"Table already exists in room \"[1]\"",
"error_table_exists_merged":"Table already exists in room \"[1]\", it is merged with table [2].", "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_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]?", "confirm_delete_table":"Are you sure you want to delete table [1]?",
"orig_qty_header":"Original Qty", "orig_qty_header":"Original Qty",
"selected_qty_header":"Selected 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]", "logged_in_as":"Logged in as [1]",
"covers":"[1] Covers", "covers":"[1] Covers",
"selected_cover":"Cover [1]", "selected_cover":"Cover [1]",
"activeTable":"Table [1]", "active_table":"Table [1]",
"totalPrice":"Total Price: [1]", "totalPrice":"Total Price: [1]",
"selectedPrice":"([1] Selected)", "selectedPrice":"([1] Selected)",
"next_page":"Next Page", "next_page":"Next Page",
@@ -60,7 +60,8 @@
"delete_table":"Delete Table", "delete_table":"Delete Table",
"change_shape":"Change Shape", "change_shape":"Change Shape",
"new_table_number":"New Table Number", "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", "add_decoration":"Add Decoration",
"choose_decoration":"Choose a Decoration", "choose_decoration":"Choose a Decoration",
"delete_decoration":"Delete Decoration", "delete_decoration":"Delete Decoration",
@@ -68,9 +69,11 @@
"reserved_for":"Reserved for [1]", "reserved_for":"Reserved for [1]",
"reserved":"Reserved", "reserved":"Reserved",
"confirm_delete_reservation":"Are you sure you want to delete the reservation on table [1]?", "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":"Table already exists in room \"[1]\"",
"error_table_exists_merged":"Table already exists in room \"[1]\", it is merged with table [2].", "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_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]?", "confirm_delete_table":"Are you sure you want to delete table [1]?",
"orig_qty_header":"Original Qty", "orig_qty_header":"Original Qty",
"selected_qty_header":"Selected Qty", "selected_qty_header":"Selected Qty",

View File

@@ -1,11 +1,11 @@
let Application = { let Application = {
keyboard: null, keyboard: null,
mode: "default", mode: [],
languageVars: {} languageVars: {}
}; };
/** Parses a language variable. */ /** Parses a language variable. */
let lang = (key, replacements) => { let lang = (key, replacements) => {
let finalValue = Application.languageVars[key]; let finalValue = Application.languageVars[key] || '';
if (!replacements) if (!replacements)
return finalValue; return finalValue;
if (typeof replacements === 'string') if (typeof replacements === 'string')
@@ -28,16 +28,19 @@ let ajax = (endpoint, data, method = 'POST', successFunction, errorFunction, bef
method: method, method: method,
data: data, data: data,
success: (response) => { success: (response) => {
if (successFunction) if (successFunction && response.status == 'success')
successFunction(JSON.parse(response.data)); 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 beforeSend: beforeFunction
}); });
}; };
/* /*
For the flow of the app, synchronous is commonly preferred 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 ajaxSync = (endpoint, data, method = 'POST') => {
let response = JSON.parse($.ajax({ let response = JSON.parse($.ajax({
@@ -56,11 +59,14 @@ let ajaxSync = (endpoint, data, method = 'POST') => {
let redirect = (url) => { let redirect = (url) => {
window.location.href = url; window.location.href = url;
}; };
let setLanguageVariables = () => { let setupCore = (languageVars) => {
Application.languageVars = ajaxSync('/ajax/languageVars', null, 'GET'); Application.languageVars = languageVars;
const doc = $(document);
doc.on('click', '#alertNo, #alertOk', hideAlerts);
setElementVisibilityByMode();
}; };
// @ts-ignore // @ts-ignore
let alert = (message, title = 'Message') => { let posAlert = (message, title = 'Message') => {
let alertBox = $('#alert'); let alertBox = $('#alert');
alertBox.css('display', 'flex'); alertBox.css('display', 'flex');
alertBox.data('value', ''); alertBox.data('value', '');
@@ -70,12 +76,11 @@ let alert = (message, title = 'Message') => {
$('#alertYes').css('display', 'none'); $('#alertYes').css('display', 'none');
$('#alertNo').css('display', 'none'); $('#alertNo').css('display', 'none');
}; };
// @ts-ignore let confirmation = (message, data, title = 'Confirm', submitFunction = (data) => { hideAlerts(); }) => {
let confirm = (message, data, title = 'Confirm', submitFunction = (data) => { hideAlerts(); }) => {
let alert = $('#alert'); let alert = $('#alert');
$(document).on('click', '#alert #alertYes', () => { $(document).on('click', '#alert #alertYes', () => {
submitFunction(data);
hideAlerts(); hideAlerts();
submitFunction(data);
$(document).off('click', '#alert #alertYes'); $(document).off('click', '#alert #alertYes');
}); });
alert.css('display', 'flex'); alert.css('display', 'flex');
@@ -85,12 +90,58 @@ let confirm = (message, data, title = 'Confirm', submitFunction = (data) => { hi
$('#alertYes').css('display', 'flex'); $('#alertYes').css('display', 'flex');
$('#alertNo').css('display', 'flex'); $('#alertNo').css('display', 'flex');
}; };
let hideAlerts = () => { let hideAlerts = () => $('#alert').hide();
$('#alert').hide(); let turnOnMode = (mode) => {
Application.mode.push(mode);
setElementVisibilityByMode();
}; };
$(() => { let turnOffMode = (mode) => {
let doc = $(document); Application.mode = Application.mode.filter((value) => value != mode);
setLanguageVariables(); setElementVisibilityByMode();
doc.on('click', '#alertNo, #alertOk', () => $('#alert').hide()); };
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 //# 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('submitfunction', submitFunction);
numpad.data('password', isPassword); numpad.data('password', isPassword);
numpad.data('allowdecimals', allowDecimals); numpad.data('allowdecimals', allowDecimals);
$(document).unbind('keyup'); $(document).off('keyup');
$(document).keyup(e => { $(document).on('keyup', e => {
let key = e.key; let key = e.key;
switch (key) { switch (key) {
case 'Backspace': case 'Backspace':
@@ -52,7 +52,6 @@ let virtualNumpadInput = (input) => {
let submitFunction = numpad.data('submitfunction'); let submitFunction = numpad.data('submitfunction');
let allowedValues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'submit', 'clear']; let allowedValues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'submit', 'clear'];
let currentValue = numpad.data('value').toString(); let currentValue = numpad.data('value').toString();
//Test
if (allowDecimals) if (allowDecimals)
allowedValues.push('.', ','); allowedValues.push('.', ',');
let validInput = allowedValues.includes(input); let validInput = allowedValues.includes(input);
@@ -91,11 +90,12 @@ let setupVirtualNumpad = () => {
hideVirtualNumpad(); hideVirtualNumpad();
}); });
}; };
let setupVirtualKeyboard = () => { let setupVirtualKeyboard = (keyboardLayouts) => {
Application.keyboard = { Application.keyboard = {
capsLock: false, capsLock: false,
shift: false, shift: false,
layout: 'default' layouts: keyboardLayouts,
currentLayout: 'default',
}; };
$(document).on('click', '.virtualKeyboardButton', e => { $(document).on('click', '.virtualKeyboardButton', e => {
virtualKeyboardInput($(e.target).data('value')); virtualKeyboardInput($(e.target).data('value'));
@@ -138,7 +138,7 @@ let virtualKeyboardInput = (input) => {
case 'submit': case 'submit':
hideVirtualKeyboard(); hideVirtualKeyboard();
let submitFunction = keyboard.data('submitfunction'); let submitFunction = keyboard.data('submitfunction');
submitFunction(); submitFunction(inputBox.text());
break; break;
case 'shift': case 'shift':
if (Application.keyboard.capsLock) if (Application.keyboard.capsLock)
@@ -174,16 +174,17 @@ let virtualKeyboardInput = (input) => {
} }
}; };
let setKeyboardLayout = (layout, modifier = '') => { let setKeyboardLayout = (layout, modifier = '') => {
let keyboardLayout = ajaxSync('/languages/english/keyboardLayout.json', null, 'get');
if (modifier != '') if (modifier != '')
modifier = `_${modifier}`; modifier = `_${modifier}`;
Application.keyboard.currentLayout = layout;
let layoutToLoad = Application.keyboard.layouts[layout];
$('.virtualKeyboardRow').each((index, row) => { $('.virtualKeyboardRow').each((index, row) => {
/* /*
We start at 1 instead of 0. Makes it easier for non-programmers We start at 1 instead of 0. Makes it easier for non-programmers
and translators making their own language packs and translators making their own language packs
*/ */
index = index + 1; index = index + 1;
let currentRow = keyboardLayout[layout]["row" + index + modifier]; let currentRow = layoutToLoad[`row${index}${modifier}`];
$(row).children('a').each((keyIndex, button) => { $(row).children('a').each((keyIndex, button) => {
let key = $(button); let key = $(button);
let keyValue = currentRow[keyIndex]; let keyValue = currentRow[keyIndex];
@@ -211,6 +212,6 @@ let setKeyboardLayout = (layout, modifier = '') => {
}; };
$(() => { $(() => {
setupVirtualNumpad(); setupVirtualNumpad();
setupVirtualKeyboard(); ajax('/ajax/getKeyboardLayout/english', null, 'get', setupVirtualKeyboard, null, null);
}); });
//# sourceMappingURL=keyboards.js.map //# sourceMappingURL=keyboards.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,13 +1,13 @@
let Application : ApplicationState = { let Application : ApplicationState = {
keyboard : null, keyboard : null,
mode: "default", mode: [],
languageVars: {} languageVars: {}
} }
/** Parses a language variable. */ /** Parses a language variable. */
let lang = (key: string, replacements?: string[] | string) => { let lang = (key: string, replacements?: string[] | string) => {
let finalValue = Application.languageVars[key] let finalValue = Application.languageVars[key] || ''
if(!replacements) return finalValue if(!replacements) return finalValue
if(typeof replacements === 'string') replacements = [replacements] if(typeof replacements === 'string') replacements = [replacements]
@@ -26,17 +26,20 @@
} }
/** Call an Ajax function asynchronously */ /** 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) data = (data == null) ? data : JSON.stringify(data)
return $.ajax({ return $.ajax({
url: endpoint, url: endpoint,
method: method, method: method,
data: data, data: data,
success: (response) => { success: (response: ajaxResult) => {
if(successFunction) if(successFunction && response.status == 'success')
successFunction(JSON.parse(response.data)) 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 beforeSend: beforeFunction
}) })
} }
@@ -44,7 +47,7 @@
/* /*
For the flow of the app, synchronous is commonly preferred 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 ajaxSync = (endpoint : string, data?: any, method = 'POST') => {
let response = JSON.parse( let response = JSON.parse(
@@ -69,12 +72,17 @@
} }
let setLanguageVariables = () => { let setupCore = (languageVars: Record<string, string>) => {
Application.languageVars = ajaxSync('/ajax/languageVars', null, 'GET') Application.languageVars = languageVars
const doc = $(document)
doc.on('click', '#alertNo, #alertOk', hideAlerts)
setElementVisibilityByMode()
} }
// @ts-ignore // @ts-ignore
let alert = (message: string, title='Message') => { let posAlert = (message: string, title='Message') => {
let alertBox = $('#alert') let alertBox = $('#alert')
alertBox.css('display', 'flex'); alertBox.css('display', 'flex');
alertBox.data('value', ''); alertBox.data('value', '');
@@ -86,13 +94,12 @@
$('#alertNo').css('display', 'none'); $('#alertNo').css('display', 'none');
} }
// @ts-ignore let confirmation = (message: string, data: any, title='Confirm', submitFunction = (data: any) => {hideAlerts()}) => {
let confirm = (message: string, data: any, title='Confirm', submitFunction = (data: any) => {hideAlerts()}) => {
let alert = $('#alert') let alert = $('#alert')
$(document).on('click', '#alert #alertYes', () => { $(document).on('click', '#alert #alertYes', () => {
submitFunction(data)
hideAlerts() hideAlerts()
submitFunction(data)
$(document).off('click', '#alert #alertYes') $(document).off('click', '#alert #alertYes')
}) })
@@ -106,13 +113,69 @@
} }
let hideAlerts = () => { let hideAlerts = () => $('#alert').hide()
$('#alert').hide()
let turnOnMode = (mode : PosMode) => {
Application.mode.push(mode)
setElementVisibilityByMode()
} }
$( () => { let turnOffMode = (mode : PosMode) => {
let doc = $(document) Application.mode = Application.mode.filter((value) => value != mode)
setLanguageVariables() 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 numpad = $('#virtualNumpad');
let inputBox = $('#virtualNumpadInput') let inputBox = $('#virtualNumpadInput')
let closeKeyboardButton = $('.closeKeyboards') let closeKeyboardButton = $('.closeKeyboards')
@@ -23,10 +28,9 @@
numpad.data('password', isPassword); numpad.data('password', isPassword);
numpad.data('allowdecimals', allowDecimals); numpad.data('allowdecimals', allowDecimals);
$(document).unbind('keyup'); $(document).off('keyup');
$(document).keyup(e => { $(document).on('keyup', e => {
let key = e.key; let key = e.key;
switch (key) { switch (key) {
case 'Backspace': case 'Backspace':
case 'Delete': case 'Delete':
@@ -64,7 +68,7 @@
let submitFunction = numpad.data('submitfunction') let submitFunction = numpad.data('submitfunction')
let allowedValues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'submit', 'clear'] let allowedValues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'submit', 'clear']
let currentValue = numpad.data('value').toString() let currentValue = numpad.data('value').toString()
//Test
if (allowDecimals) if (allowDecimals)
allowedValues.push('.', ',') allowedValues.push('.', ',')
@@ -109,11 +113,12 @@
}); });
} }
let setupVirtualKeyboard = () => { let setupVirtualKeyboard = (keyboardLayouts: VirtualKeyboard) => {
Application.keyboard = { Application.keyboard = {
capsLock: false, capsLock: false,
shift: false, shift: false,
layout: 'default' layouts: keyboardLayouts,
currentLayout: 'default',
} }
$(document).on('click', '.virtualKeyboardButton', e => { $(document).on('click', '.virtualKeyboardButton', e => {
@@ -123,7 +128,7 @@
setKeyboardLayout('default') setKeyboardLayout('default')
} }
let showVirtualKeyboard = (heading: string, maxlength = 32, isPassword = false, submitFunction = () => { let showVirtualKeyboard = (heading: string, maxlength = 32, isPassword = false, submitFunction :Function = () => {
hideVirtualKeyboard() hideVirtualKeyboard()
}) => { }) => {
let keyboard = $('#virtualKeyboard') let keyboard = $('#virtualKeyboard')
@@ -166,7 +171,7 @@
case 'submit': case 'submit':
hideVirtualKeyboard(); hideVirtualKeyboard();
let submitFunction = keyboard.data('submitfunction') let submitFunction = keyboard.data('submitfunction')
submitFunction(); submitFunction(inputBox.text());
break; break;
case 'shift': case 'shift':
if (Application.keyboard.capsLock) break; if (Application.keyboard.capsLock) break;
@@ -206,8 +211,10 @@
} }
let setKeyboardLayout = (layout: string, modifier = '') => { let setKeyboardLayout = (layout: string, modifier = '') => {
let keyboardLayout = ajaxSync('/languages/english/keyboardLayout.json', null, 'get')
if (modifier != '') modifier = `_${modifier}` if (modifier != '') modifier = `_${modifier}`
Application.keyboard.currentLayout = layout
let layoutToLoad = Application.keyboard.layouts[layout]
$('.virtualKeyboardRow').each((index, row) => { $('.virtualKeyboardRow').each((index, row) => {
/* /*
@@ -215,7 +222,7 @@
and translators making their own language packs and translators making their own language packs
*/ */
index = index + 1; 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) => { $(row).children('a').each((keyIndex, button) => {
let key = $(button); let key = $(button);
@@ -252,5 +259,5 @@
$(() => { $(() => {
setupVirtualNumpad() 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 { interface ajaxResult {
status: string status: string
@@ -7,11 +8,10 @@ interface ajaxResult {
interface ApplicationState { interface ApplicationState {
keyboard: keyboard keyboard: keyboard
mode: PosMode mode: PosModes
languageVars: Record<any, string> languageVars: Record<any, string>
} }
interface table { interface table {
table_number: number, table_number: number,
room_id: number room_id: number
@@ -25,20 +25,41 @@ interface table {
rotation: number rotation: number
merged_children: string merged_children: string
previous_state: string previous_state: string
status: string status: number
table_id: 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 { interface room {
room_id: number id: number
room_name: string room_name: string
background_image: string background_image: string
venue_id: number 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 { interface keyboard {
capsLock: boolean capsLock: boolean
shift: boolean shift: boolean
layout: string layouts: VirtualKeyboard
currentLayout: string
} }

View File

@@ -553,14 +553,14 @@ a.logOut{
.floorplanControls, .floorplanControls,
.mergeControls{ .mergeControls{
visibility:hidden;
width:100%; width:100%;
flex-basis:33%; flex-basis:33%;
display:flex; display:flex;
flex-direction:column; flex-direction:column;
} }
.editControls a{ .editControls > a,
.editControls .posHeader{
height:100%; height:100%;
display:flex; display:flex;
flex-wrap:wrap; flex-wrap:wrap;
@@ -568,12 +568,23 @@ a.logOut{
align-items:center; align-items:center;
justify-content:center; justify-content:center;
text-align:center; text-align:center;
padding:0.5em;
} }
.editControls .posHeader{ .editControls .posHeader{
flex-direction:column; 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, .floorplanControls a,
.mergeControls a{ .mergeControls a{
display:flex; display:flex;

View File

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