22 Commits

Author SHA1 Message Date
e3794fc222 Unversioned file was tracking 2022-02-13 19:35:02 +10:00
39dbba45f7 Separated models, controllers and routers 2022-02-13 19:33:50 +10:00
dredgy
6cbd670260 Merge pull request #3 from dredgy/order_screen
Join With Line function
2022-02-13 13:10:24 +10:00
430ad87880 Join With Line function 2022-02-13 13:09:53 +10:00
dredgy
abfb2331ba Merge pull request #2 from dredgy/order_screen
Order screen
2022-01-23 18:18:06 +10:00
445cbbabe5 OrderScreen complete 2022-01-23 18:16:18 +10:00
75c129c5d4 Updates to scaling on phones 2022-01-11 06:51:55 +10:00
56d42f1339 Added open food/freetext commands 2022-01-08 19:25:01 +10:00
f656c5ab40 Added print group overrides 2022-01-08 17:53:23 +10:00
198d609e62 Added mutation observer to sum totals 2022-01-07 10:41:49 +10:00
fc4a5d8624 Finalization of order box behavior 2022-01-06 12:01:09 +10:00
30bc79ef98 Finished void functionality 2022-01-05 14:54:40 +10:00
85722fa692 Updates to order screen 2022-01-04 15:04:55 +10:00
4de8f20d00 Fixed data-item attribute 2022-01-02 20:05:21 +10:00
3067bd1bfc Repair 2022-01-02 16:17:18 +10:00
21cd4b2018 Minor syntax 2022-01-02 15:19:10 +10:00
cbd157d2c9 Updated to F# 6 arrays 2022-01-02 15:17:36 +10:00
bb5e613382 Images 2022-01-01 21:58:20 +10:00
969e6b1b87 Converted from MySQL to PgSQL 2021-11-28 16:50:58 +10:00
db1b620aec images 2021-11-22 10:05:32 +10:00
a48c3a68e0 Added Basic Order Screen 2021-11-21 20:44:44 +10:00
dd1ed266f8 Updates 2021-11-12 21:25:04 +10:00
170 changed files with 2525 additions and 1088 deletions

1
.gitignore vendored
View File

@@ -8,3 +8,4 @@
/.idea/ /.idea/
/wwwroot/scripts/js/ /wwwroot/scripts/js/
/wwwroot/styles/css/* /wwwroot/styles/css/*
/Folder.DotSettings.user

15
Ajax/Controller.fs Normal file
View File

@@ -0,0 +1,15 @@
module DredgePos.Ajax.Controller
open DredgeFramework
open language
open Giraffe
let getLanguageVars = ajaxSuccess languageVars
let getKeyboardLayout (language: string) =
let layout = $"""wwwroot/languages/{language}/keyboardLayout.json"""
|> GetFileContents
map [
"status", "success"
"data", layout
] |> json

14
Ajax/Router.fs Normal file
View File

@@ -0,0 +1,14 @@
module DredgePos.Ajax.Router
open Saturn
open Giraffe
let pipeline = pipeline {
use_warbler
}
let router = router {
getf "/getKeyboardLayout/%s" Controller.getKeyboardLayout
get "/languageVars" (json Controller.getLanguageVars)
}

View File

@@ -1,148 +0,0 @@
module AjaxController
open DredgeFramework
open DredgePos
open Floorplan
open Microsoft.AspNetCore.Http
open Reservations
open language
open Giraffe
open Types
let loginWithLoginCode (context: HttpContext) (login_code: int) =
if Session.clerkLogin login_code context then ajaxSuccess "success"
else ajaxFail "fail"
let getLanguageVars = ajaxSuccess languageVars
let getActiveTables venue = Floorplan.getActiveTables venue |> ajaxSuccess |> json
let getRoomData roomId = Floorplan.getRoom roomId |> ajaxSuccess |> json
let mergeTables (tables: floorplan_table[]) =
let status =
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;
]
ajaxSuccess outputTables
else ajaxFail "Could Not Merge Tables"
status |> json
let unmergeTable tableNumber =
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"
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
let data = {|
tables = tables
decorations = decorations
|}
data |> ajaxSuccess |> json
let getTableData tableNumber = json <| Floorplan.getTable tableNumber
let updateTableShape (table: floorplan_table) =
Floorplan.updateTableShape table |> ignore
getTableData table.table_number
let transformTable (table: floorplan_table) =
Floorplan.updateTablePosition table |> ignore
getTableData table.table_number
let createTable (tableData: floorplan_table) =
let result =
if tableExists tableData.table_number = "False" then
ajaxSuccess (addNewTable tableData)
else ajaxFail (tableExists tableData.table_number)
result |> json
let deleteTable (table: floorplan_table) =
Floorplan.deleteTable table.table_number
table |> ajaxSuccess |> json
let transferTable (origin, destination) =
Floorplan.transferTable origin destination
let data = map ["origin", getTable origin ; "destination", getTable destination]
ajaxSuccess data |> json
let AddDecoration (data: floorplan_decoration) =
let image = "wwwroot/images/decorations/" + data.decoration_image
let width, height = image |> GetImageSize
let aspectRatio = decimal width / decimal height
let decoration : floorplan_decoration = {
id = 0
decoration_height = (200m / aspectRatio) |> int
decoration_width = 200
decoration_rotation = 0
decoration_image = data.decoration_image
decoration_pos_x = data.decoration_pos_x
decoration_pos_y = data.decoration_pos_y
decoration_room = data.decoration_room
}
Decorations.CreateDecoration decoration |> ajaxSuccess |> json
let UpdateDecoration data =
Decorations.UpdateDecoration data |> ignore
ajaxSuccess "true" |> json
let DeleteDecoration id = ajaxSuccess (Decorations.DeleteDecoration id) |> json
let newEmptyReservation (reservation: reservation) =
let newReservation = {reservation with
reservation_created_at = CurrentTime()
reservation_time = CurrentTime()
}
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

@@ -0,0 +1,17 @@
module DredgePos.Authenticate.Controller
open Giraffe
open DredgeFramework
open Microsoft.AspNetCore.Http
let loadAuthenticatePage (): HttpHandler =
let variables = map ["title", "Log In"]
let scripts = ["dredgepos.authenticate.js"]
let styles = ["dredgepos.authenticate.css"]
Theme.loadTemplateWithVarsScriptsAndStyles "authenticate" variables scripts styles
|> htmlString
let loginWithLoginCode (context: HttpContext) (login_code: int) =
if Model.clerkLogin login_code context then ajaxSuccess "success"
else ajaxFail "fail"

View File

@@ -1,13 +1,27 @@
module Session module DredgePos.Authenticate.Model
open System open System
open DredgeFramework open DredgeFramework
open Dapper.FSharp open Dapper.FSharp
open Clerk
open DredgePos open DredgePos
open Thoth.Json.Net open Thoth.Json.Net
open Types open Types
let getClerkByLoginCode (loginCode: int) =
let clerk =
select {
table "clerks"
where (eq "clerk_login_code" loginCode)
take 1
}
|> db.Select<clerk>
|> EnumerableToArray
if (clerk |> length) > 0 then
Some (first clerk)
else
None
let deleteSession sessionId context = let deleteSession sessionId context =
delete { delete {
table "sessions" table "sessions"
@@ -65,12 +79,10 @@ 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 existingClerk.IsSome
&& existingClerk.Value.id = 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
else false
let getLoginCookie context = Browser.getCookie "dredgepos_clerk_logged_in" context let getLoginCookie context = Browser.getCookie "dredgepos_clerk_logged_in" context

18
Authenticate/Router.fs Normal file
View File

@@ -0,0 +1,18 @@
module DredgePos.Authenticate.Router
open Saturn
open Giraffe
let homepage = (warbler (fun _ -> Controller.loadAuthenticatePage() ))
let handlePostRoute<'a> handlerFunction post next ctx = json (handlerFunction ctx post) next ctx
let pipeline = pipeline{
use_warbler
}
let router = router {
pipe_through pipeline
get "/" homepage
get "" homepage
post "/authenticateClerk" (bindJson<int> (handlePostRoute Controller.loginWithLoginCode) )
}

View File

@@ -1,50 +0,0 @@
module Browser
open System
open System.IO
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Http
open Microsoft.AspNetCore.Routing
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
open DredgeFramework
let cookieExists name (context: HttpContext) =
context.Request.Cookies.ContainsKey(name)
let deleteCookie name (context: HttpContext) =
if cookieExists name context then context.Response.Cookies.Delete(name)
let getCookie cookieName (context: HttpContext) =
context.Request.Cookies.[cookieName] |? ""
let setCookie name value (expiry: DateTimeOffset) (context: HttpContext) =
deleteCookie name context
let options = CookieOptions()
options.Expires <- expiry
context.Response.Cookies.Append(name, value, options);
let redirect url (context: HttpContext) =
context.Response.Redirect url
let addRoute path controller (endpoints: IEndpointRouteBuilder) =
endpoints.MapGet(path, fun context ->
context.Response.WriteAsync(controller())) |> ignore
endpoints
let addRouteWithParameter path controller param1 (endpoints: IEndpointRouteBuilder) =
endpoints.MapGet(path, fun context ->
let param1Name, param1Type = param1
let parameter1 = context.Request.RouteValues.[param1Name] |> string |> param1Type
context.Response.WriteAsync(controller parameter1)) |> ignore
endpoints
let addRouteWithParameters path controller param1 param2 (endpoints: IEndpointRouteBuilder) =
endpoints.MapGet(path, fun context ->
let param1Name, param1Type = param1
let param2Name, param2Type = param2
let parameter1 = context.Request.RouteValues.[param1Name] |> string |> param1Type
let parameter2 = context.Request.RouteValues.[param2Name] |> string |> param2Type
context.Response.WriteAsync(controller parameter1 parameter2)) |> ignore
endpoints

View File

@@ -1,37 +0,0 @@
module Clerk
open Dapper.FSharp
open DredgeFramework
open DredgePos
open Thoth.Json.Net
open Types
let mutable loginCookie = ""
let clerk_decoder : Decoder<clerk> =
Decode.object
(fun get ->
{
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
})
type user = {clerk_name:string}
let getClerkByLoginCode (loginCode: int) =
let clerk =
select {
table "clerks"
where (eq "clerk_login_code" loginCode)
take 1
}
|> db.Select<clerk>
|> EnumerableToArray
if (clerk |> length) > 0 then
Some (first clerk)
else
None

29
Core/Browser.module.fs Normal file
View File

@@ -0,0 +1,29 @@
module Browser
open System
open System.IO
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Http
open Microsoft.AspNetCore.Routing
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
open DredgeFramework
let cookieExists name (context: HttpContext) =
context.Request.Cookies.ContainsKey(name)
let deleteCookie name (context: HttpContext) =
if cookieExists name context then context.Response.Cookies.Delete(name)
let getCookie cookieName (context: HttpContext) =
context.Request.Cookies[cookieName] |? ""
let setCookie name value (expiry: DateTimeOffset) (context: HttpContext) =
deleteCookie name context
let options = CookieOptions()
options.Expires <- expiry
context.Response.Cookies.Append(name, value, options);
let redirect url (context: HttpContext) =
context.Response.Redirect url

View File

@@ -2,12 +2,14 @@
open Dapper open Dapper
open Dapper.FSharp open Dapper.FSharp
open Dapper.FSharp.MySQL open Dapper.FSharp.PostgreSQL
open MySql.Data.MySqlClient
open DredgeFramework open DredgeFramework
let connString = "server=localhost;uid=root;pwd=;database=dredgepos;table cache = false" let connString = "Server=localhost;Port=5432;User Id=postgres;Password=root;Database=dredgepos;Include Error Detail=true"
let connection = new MySqlConnection(connString) //let connString = "server=localhost;uid=root;pwd=;database=dredgepos;table cache = false"
let connection = new Npgsql.NpgsqlConnection(connString)
let Select<'a> asyncQuery = let Select<'a> asyncQuery =
asyncQuery asyncQuery
@@ -28,18 +30,15 @@ let Insert<'a> asyncQuery =
let InsertOutput<'a> asyncQuery = let InsertOutput<'a> asyncQuery =
asyncQuery asyncQuery
|> connection.InsertAsync<'a> |> connection.InsertOutputAsync<'a, 'a>
|> RunSynchronously |> RunSynchronously
|> ignore
let table = asyncQuery.Table
connection.Query<'a>($"""Select * From {table} Where id = (select last_insert_id())""")
|> EnumerableToArray |> EnumerableToArray
let Update<'a> asyncQuery = let Update<'a> asyncQuery =
asyncQuery asyncQuery
|> connection.UpdateAsync<'a> |> connection.UpdateOutputAsync<'a, 'a>
|> RunSynchronously |> RunSynchronously
|> EnumerableToArray
let Delete<'a> asyncQuery = let Delete<'a> asyncQuery =
asyncQuery asyncQuery

View File

@@ -16,6 +16,10 @@ open Thoth.Json.Net
let (|?) lhs rhs = if lhs = null then rhs else lhs let (|?) lhs rhs = if lhs = null then rhs else lhs
let joinWithNewLine (arr: string[]) = arr |> String.concat "\n"
let getCurrentVenue () = 1
let map list = list |> Map.ofList let map list = list |> Map.ofList
let JoinArray (char: string) (array: 'a[]) = String.Join(char, array) let JoinArray (char: string) (array: 'a[]) = String.Join(char, array)
@@ -35,9 +39,11 @@ 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 first (array: 'a[]) = array[0]
let last (array: 'a[]) = array.[array.Length-1]
let last (array: 'a[]) = array[array.Length-1]
let filterFirst (array:'a[]) = if array.Length > 0 then [|array[0]|] else [||]
let removeFalseValues (variable: bool[]) = variable |> Array.filter id let removeFalseValues (variable: bool[]) = variable |> Array.filter id

View File

@@ -0,0 +1,76 @@
module Entity
open Dapper.FSharp
open DredgeFramework
open Pluralize.NET.Core
open FSharp.Reflection
let GetDatabaseTable<'x> =
let typeName = typeof<'x>.Name
Pluralizer().Pluralize typeName
let Create (record: 'x)=
let tableName = GetDatabaseTable<'x>
insert {
table tableName
value record
excludeColumn "id"
}
|> db.InsertOutput
|> first
let inline Update (record: ^x) =
let tableName = GetDatabaseTable<'x>
let id = ((^x) : (member id : int) record)
update {
table tableName
set record
where (eq "id" id)
excludeColumn "id"
}
|> db.Update
let GetAll<'x> =
let tableName = GetDatabaseTable<'x>
select {
table tableName
}
|> db.Select<'x>
let GetAllByColumn<'x> (column: string) (value: obj) =
let tableName = GetDatabaseTable<'x>
select {
table tableName
where (eq column value)
} |> db.Select<'x>
let GetAllInVenue<'x> = GetAllByColumn<'x> "venue_id" (getCurrentVenue ())
let GetById<'x> (id: int) = GetAllByColumn<'x> "id" id |> first
let inline GetRelated<'x, .. > (entity: ^y) =
let columnName = typeof<'x>.Name + "_id"
let primaryKeyValue = typeof<'y>.GetProperty(columnName).GetValue(entity) :?> int
GetById<'x> primaryKeyValue
let inline GetAllRelated<'x, .. > (entity: ^y) =
let id = typeof<'y>.GetProperty("id").GetValue(entity) :?> int
let columnName = typeof<'y>.Name + "_id"
GetAllByColumn<'x> columnName id
let DeleteById<'x> id =
let typeName = typeof<'x>.Name
let tableName = Pluralizer().Pluralize typeName
let entity = GetById<'x> id
delete {
table tableName
where (eq "id" id)
} |> db.Delete |> ignore
entity
let inline Delete< ^x when ^x: (member id: int) > (entity: ^x) =
typeof<'x>.GetProperty("id").GetValue(entity) :?> int
|> DeleteById<'x>

View File

@@ -19,15 +19,15 @@ let languageVars =
//Gets a value of a language variable //Gets a value of a language variable
let get var = let get var =
if languageVars.ContainsKey var then if languageVars.ContainsKey var then
languageVars.[var] languageVars[var]
else else
"Missing language variable: " + var "Missing language variable: " + var
let getAndReplace languageVar replacements = let getAndReplace languageVar (replacements: 'x list) =
let langString = get languageVar let langString = get languageVar
replacements replacements
|> List.mapi (fun index string |> List.mapi (fun index replacement
-> index + 1, string) -> index + 1, replacement.ToString())
|> List.fold (fun (result: string) (index, string) |> List.fold (fun (result: string) (index, string)
-> result.Replace($"[{index}]", string) -> result.Replace($"[{index}]", string)
) langString ) langString

View File

@@ -1,6 +1,6 @@
module Theme module Theme
open System open System.Web
open System.IO open System.IO
open System.Collections.Generic open System.Collections.Generic
open System.Text.RegularExpressions open System.Text.RegularExpressions
@@ -17,7 +17,7 @@ let getHTMLForFile file =
match scriptFileExists with match scriptFileExists with
| true -> | true ->
match fileExtension with match fileExtension with
| ".css" -> $"\t<link test rel=\"stylesheet\" href=\"{stylePath}\" />" | ".css" -> $"\t<link rel=\"stylesheet\" href=\"{stylePath}\" />"
| ".js" -> | ".js" ->
let snippet = $"\t<script src=\"{scriptPath}\"></script>" let snippet = $"\t<script src=\"{scriptPath}\"></script>"
snippet snippet
@@ -26,7 +26,7 @@ let getHTMLForFile file =
let ParseScriptsAndStylesheets files html = let ParseScriptsAndStylesheets files html =
let defaultScriptsAndStyles = ["dark.theme.css"; "external/jquery.js" ; "dredgepos.core.js"; "keyboards.js";] let defaultScriptsAndStyles = ["dark.theme.css"; "../external/jquery.js" ; "dredgepos.core.js"; "keyboards.js";]
let scriptsAndStylesheets = defaultScriptsAndStyles @ files let scriptsAndStylesheets = defaultScriptsAndStyles @ files
let scriptAndStylesheetHTML = let scriptAndStylesheetHTML =
@@ -43,24 +43,24 @@ let ParseVariables (varArray: Map<string, string>) (html:string) =
Regex.Replace(html, "<!--\[var\:(.*?)\]-->", Regex.Replace(html, "<!--\[var\:(.*?)\]-->",
MatchEvaluator( MatchEvaluator(
fun matchedVar -> fun matchedVar ->
let varName = matchedVar.Groups.[1] |> string |> StringTrim let varName = matchedVar.Groups[1] |> string |> StringTrim
if varArray.ContainsKey varName then if varArray.ContainsKey varName then
if varName |> ToLowerCase = "title" then titlePrefix varArray.[varName] if varName |> ToLowerCase = "title" then titlePrefix varArray[varName]
else varArray.[varName] else varArray[varName]
else else
"<!--[Undefined Variable: " + varName + "]-->" ""
)) ))
let ParseArrays (arrayArray: Map<string, Map<string, string>>) (string:string) = let ParseArrays (arrayArray: Map<string, Map<string, string>>) (string:string) =
Regex.Replace(string, "<!--\[arr\:(.*?)\|(.*?)\]-->", Regex.Replace(string, "<!--\[arr\:(.*?)\|(.*?)\]-->",
MatchEvaluator( MatchEvaluator(
fun matchedVar -> fun matchedVar ->
let arrayName = matchedVar.Groups.[1].ToString() |> StringTrim let arrayName = matchedVar.Groups[1].ToString() |> StringTrim
let keyName = matchedVar.Groups.[2].ToString() let keyName = matchedVar.Groups[2].ToString()
if arrayArray.ContainsKey arrayName && arrayArray.[arrayName].ContainsKey keyName then if arrayArray.ContainsKey arrayName && arrayArray[arrayName].ContainsKey keyName then
arrayArray.[arrayName].[keyName] arrayArray[arrayName][keyName]
else else
"<!--[Undefined Array: " + arrayName + "]-->" "<!--[Undefined Array: " + arrayName + "]-->"
) )
@@ -70,7 +70,7 @@ let ParseSimpleLanguageVariables (string:string) =
Regex.Replace(string, "<!--\[lang\:(.*?)\]-->", Regex.Replace(string, "<!--\[lang\:(.*?)\]-->",
new MatchEvaluator( new MatchEvaluator(
fun matchedVar -> fun matchedVar ->
let varName = matchedVar.Groups.[1].ToString() let varName = matchedVar.Groups[1].ToString()
|> StringTrim |> StringTrim
language.get varName language.get varName
@@ -78,10 +78,10 @@ let ParseSimpleLanguageVariables (string:string) =
let ParseLanguageVariablesWithReplacements (string: string) = let ParseLanguageVariablesWithReplacements (string: string) =
Regex.Replace(string, "<!--\[lang\:(.*?)\|(.*?)\]-->", Regex.Replace(string, "<!--\[lang\:(.*?)\|(.*?)\]-->",
new MatchEvaluator( MatchEvaluator(
fun matchedVar -> fun matchedVar ->
let varName = matchedVar.Groups.[1].ToString() let varName = matchedVar.Groups[1].ToString()
let replacements = matchedVar.Groups.[2].ToString() let replacements = matchedVar.Groups[2].ToString()
|> StringSplit "," |> StringSplit ","
|> Array.toList |> Array.toList
@@ -115,13 +115,16 @@ let rec loadTemplateWithVarsArraysScriptsAndStyles templateName vars arrays scri
and ParseTemplates vars arrays scripts styles (string: string) = and ParseTemplates vars arrays scripts styles (string: string) =
Regex.Replace(string, "<!--\[template\:(.*?)\]-->", Regex.Replace(string, "<!--\[template\:(.*?)\]-->",
new MatchEvaluator( fun template -> new MatchEvaluator( fun template ->
let templateName = template.Groups.[1].ToString() |> StringTrim let templateName = template.Groups[1].ToString() |> StringTrim
loadTemplateWithVarsArraysScriptsAndStyles templateName vars arrays scripts styles loadTemplateWithVarsArraysScriptsAndStyles templateName vars arrays scripts styles
)) ))
let loadTemplate templateName = let loadTemplate templateName =
loadTemplateWithVarsArraysScriptsAndStyles templateName Map.empty<string, string> Map.empty<string, Map<string, string>> [] [] loadTemplateWithVarsArraysScriptsAndStyles templateName Map.empty<string, string> Map.empty<string, Map<string, string>> [] []
let loadTemplateWithArrays templateName arrays =
loadTemplateWithVarsArraysScriptsAndStyles templateName Map.empty arrays [] []
let loadTemplateWithVars templateName vars = let loadTemplateWithVars templateName vars =
loadTemplateWithVarsArraysScriptsAndStyles templateName vars Map.empty<string, Map<string, string>> [] [] loadTemplateWithVarsArraysScriptsAndStyles templateName vars Map.empty<string, Map<string, string>> [] []
@@ -135,3 +138,18 @@ let loadTemplateWithVarsAndStyles = loadTemplateWithVarsAndScripts
let loadTemplateWithVarsScriptsAndStyles templateName vars scripts styles = let loadTemplateWithVarsScriptsAndStyles templateName vars scripts styles =
loadTemplateWithVarsArraysScriptsAndStyles templateName vars Map.empty<string, Map<string, string>> scripts styles loadTemplateWithVarsArraysScriptsAndStyles templateName vars Map.empty<string, Map<string, string>> scripts styles
let htmlAttributes (attributes: Map<string, string>) =
" " + (attributes
|> Map.toArray
|> Array.map (fun (attribute, value) -> attribute+"='"+HttpUtility.HtmlEncode value + "'")
|> String.concat " ")
let PosButton (text: string) (classes: string) (attributes: string) =
let vars = map [
"text", text
"classes", classes
"attributes", attributes
]
loadTemplateWithVars "components/posButton" vars

112
Core/Types.fs Normal file
View File

@@ -0,0 +1,112 @@
module DredgePos.Types
[<CLIMutable>]
type reservation = {
id: int
name: string
time: int
covers: int
floorplan_table_id: int
created_at: int
}
[<CLIMutable>]
type venue = {
id: int
venue_name: string
}
[<CLIMutable>]
type floorplan_table = {
table_number: int
room_id: int
venue_id: int
pos_x: int
pos_y: int
shape: string
width: int
height: int
default_covers: int
rotation: int
merged_children: string
previous_state: string
status: int
id: int
}
[<CLIMutable>]
type print_group = {
id: int
name: string
printer: int
venue_id: int
}
[<CLIMutable>]
type sales_category = {
id: int
parent: int
name: string
print_group: int
venue_id: int
}
[<CLIMutable>]
type floorplan_room = {
id: int
room_name: string
background_image: string
venue_id: int
}
[<CLIMutable>]
type floorplan_decoration = {
id: int
decoration_room: int
decoration_pos_x: int
decoration_pos_y: int
decoration_rotation: int
decoration_width: int
decoration_height: int
decoration_image: string
venue_id: int
}
[<CLIMutable>]
type clerk = {id: int; clerk_name: string; clerk_login_code: int; clerk_usergroup: int}
[<CLIMutable>]
type session = {id: int; session_id: string; clerk_json: string; clerk_id: int; expires: int}
[<CLIMutable>]
type order_screen_page_group = {id: int; order: int; venue_id: int; label: string; grid_id: int}
[<CLIMutable>]
type grid = {id: int; grid_name: string; grid_rows: int; grid_cols: int; grid_data: string}
[<CLIMutable>]
type button = {
id: int
text: string
primary_action: string
primary_action_value: string
secondary_action: string
secondary_action_value: string
image: string
extra_classes: string
extra_styles: string
}
[<CLIMutable>]
type item = {
id: int
item_code: string
item_category: int
item_name: string
item_type: string
price1: int
price2: int
price3: int
price4: int
price5: int
}

View File

@@ -1,86 +0,0 @@
module Decorations
open System
open System.IO
open System.Text.RegularExpressions
open DredgeFramework
open Dapper.FSharp
open DredgePos
open Types
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 {
table "floorplan_decorations"
where (eq "decoration_room" roomId)
}
|> db.Select<floorplan_decoration>
let getImageName (image: string, path: string) =
let imageName =
image
|> StringReplace "-" " "
|> StringReplace "_" " "
|> ToTitleCase
imageName, path
let isImageFile (fileName: string) = Regex.IsMatch(fileName |> ToLowerCase, @"^.+\.(jpg|jpeg|png|gif)$")
let getImageHTML (imageName: string, imageUrl: string) =
let vars = map [
"image_name", imageName
"image_url", imageUrl
]
Theme.loadTemplateWithVars "decoratorItem" vars
let GetFileNameWithoutExtension (path: string) =
let name = Path.GetFileNameWithoutExtension path
name, path |> Path.GetFileName
let getImageRowHtml (imagesInRow: string[]) =
let vars = map ["decorations", String.Join("", imagesInRow)]
Theme.loadTemplateWithVars "decoratorRow" vars
let generateDecorator () =
"wwwroot/images/decorations"
|> Directory.GetFiles
|> Array.filter isImageFile
|> Array.map GetFileNameWithoutExtension
|> Array.map getImageName
|> Array.map getImageHTML
|> Array.chunkBySize 4
|> Array.map getImageRowHtml
|> JoinArray ""
let CreateDecoration (decoration: floorplan_decoration) =
insert {
table "floorplan_decorations"
value decoration
}
|> db.InsertOutput
|> first
let UpdateDecoration (decoration: floorplan_decoration) =
update {
table "floorplan_decorations"
set decoration
where (eq "id" decoration.id )
} |> db.Update
let DeleteDecoration (decoration: floorplan_decoration) =
delete {
table "floorplan_decorations"
where (eq "id" decoration.id)
} |> db.Delete |> ignore
decoration

View File

@@ -5,20 +5,31 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Types.fs" /> <Compile Include="Core\Types.fs" />
<Compile Include="DredgeFramework.module.fs" /> <Compile Include="Core\DredgeFramework.module.fs" />
<Compile Include="Browser.module.fs" /> <Compile Include="Core\Browser.module.fs" />
<Compile Include="Database.module.fs" /> <Compile Include="Core\Database.module.fs" />
<Compile Include="GenericEntities.module.fs" /> <Compile Include="Core\GenericEntities.module.fs" />
<Compile Include="Language.module.fs" /> <Compile Include="Core\Language.module.fs" />
<Compile Include="Theme.module.fs" /> <Compile Include="Core\Theme.module.fs" />
<Compile Include="Reservations.module.fs" /> <Compile Include="Printer.module.fs" />
<Compile Include="Floorplan.module.fs" /> <Compile Include="Entities\Floorplan_Decorations\Model.fs" />
<Compile Include="Decorations.module.fs" /> <Compile Include="Entities\Floorplan_Decorations\Controller.fs" />
<Compile Include="Clerk.module.fs" /> <Compile Include="Entities\Floorplan_Decorations\Router.fs" />
<Compile Include="Session.module.fs" /> <Compile Include="Authenticate\Model.fs" />
<Compile Include="PageController.fs" /> <Compile Include="Authenticate\Controller.fs" />
<Compile Include="AjaxController.fs" /> <Compile Include="Authenticate\Router.fs" />
<Compile Include="Ajax\Controller.fs" />
<Compile Include="Ajax\Router.fs" />
<Compile Include="Floorplan\Model.fs" />
<Compile Include="Floorplan\Controller.fs" />
<Compile Include="Floorplan\Router.fs" />
<Compile Include="OrderScreen\Model.fs" />
<Compile Include="OrderScreen\Controller.fs" />
<Compile Include="OrderScreen\Router.fs" />
<Compile Include="Reservations\Model.fs" />
<Compile Include="Reservations\Controller.fs" />
<Compile Include="Reservations\Router.fs" />
<Compile Include="Program.fs" /> <Compile Include="Program.fs" />
</ItemGroup> </ItemGroup>
@@ -34,13 +45,17 @@
</Content> </Content>
<Content Remove="node_modules\**" /> <Content Remove="node_modules\**" />
<Content Remove="wwwroot\scripts\ts\test.ts" /> <Content Remove="wwwroot\scripts\ts\test.ts" />
<Content Remove="languages\**" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Dapper" Version="2.0.78" /> <PackageReference Include="Dapper" Version="2.0.78" />
<PackageReference Include="Dapper.Contrib" Version="2.0.78" /> <PackageReference Include="Dapper.Contrib" Version="2.0.78" />
<PackageReference Include="Dapper.FSharp" Version="1.16.0" /> <PackageReference Include="Dapper.FSharp" Version="2.4.1" />
<PackageReference Include="FSharp.Data" Version="4.0.1" /> <PackageReference Include="FSharp.Data" Version="4.0.1" />
<PackageReference Include="Giraffe" Version="6.0.0-alpha-2" />
<PackageReference Include="Npgsql" Version="6.0.0" />
<PackageReference Include="Pluralize.NET.Core" Version="1.0.0" />
<PackageReference Include="Saturn" Version="0.15.0-preview03" /> <PackageReference Include="Saturn" Version="0.15.0-preview03" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.0" /> <PackageReference Include="System.Data.SqlClient" Version="4.8.0" />
<PackageReference Include="FSharp.Data.SqlClient" Version="2.1.0-beta1" /> <PackageReference Include="FSharp.Data.SqlClient" Version="2.1.0-beta1" />
@@ -54,16 +69,16 @@
<PackageReference Include="SQLProvider" Version="1.2.1" /> <PackageReference Include="SQLProvider" Version="1.2.1" />
<PackageReference Include="System.Drawing.Common" Version="6.0.0-preview.5.21301.5" /> <PackageReference Include="System.Drawing.Common" Version="6.0.0-preview.5.21301.5" />
<PackageReference Include="Thoth.Json.Net" Version="5.0.0" /> <PackageReference Include="Thoth.Json.Net" Version="5.0.0" />
<PackageReference Update="FSharp.Core" Version="6.0.2-beta.21631.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="languages\english" />
<Folder Include="tables\archived" /> <Folder Include="tables\archived" />
<Content Include="xslt\orderXMLtoHTML.xslt" /> <Content Include="xslt\orderXMLtoHTML.xslt" />
<Content Include="xslt\orderHtmltoXML.xslt" /> <Content Include="xslt\orderHtmltoXML.xslt" />
<Content Include="xslt\htmlToEscPos.xslt" /> <Content Include="xslt\htmlToEscPos.xslt" />
<Content Include=".gitignore" /> <Content Include=".gitignore" />
<Folder Include="wwwroot\scripts\js" /> <Folder Include="wwwroot\fonts" />
<Folder Include="wwwroot\styles\css" /> <Folder Include="wwwroot\styles\css" />
</ItemGroup> </ItemGroup>
@@ -375,6 +390,7 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Remove="node_modules\**" /> <EmbeddedResource Remove="node_modules\**" />
<EmbeddedResource Remove="languages\**" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

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

View File

@@ -0,0 +1,24 @@
module DredgePos.Entities.Floorplan_Decorations.Model
open System
open System.IO
open System.Text.RegularExpressions
open DredgeFramework
let decorationsInRoom (roomId: int) = Entity.GetAllByColumn "decoration_room" roomId
let getImageName (image: string, path: string) =
let imageName =
image
|> StringReplace "-" " "
|> StringReplace "_" " "
|> ToTitleCase
imageName, path
let isImageFile (fileName: string) = Regex.IsMatch(fileName |> ToLowerCase, @"^.+\.(jpg|jpeg|png|gif)$")
let GetFileNameWithoutExtension (path: string) =
let name = Path.GetFileNameWithoutExtension path
name, path |> Path.GetFileName

View File

@@ -0,0 +1,2 @@
module DredgePos.Entities.Floorplan_Decorations.Router

127
Floorplan/Controller.fs Normal file
View File

@@ -0,0 +1,127 @@
module DredgePos.Floorplan.Controller
open DredgeFramework
open DredgePos
open DredgePos.Types
open Giraffe
open Microsoft.AspNetCore.Http
open Model
let makeRoomButton (room: floorplan_room) =
let vars = map [
"roomId", room.id |> string
"roomName", room.room_name
]
Theme.loadTemplateWithVars "roomButton" vars
let getActiveTables venue = Model.getActiveTables venue |> ajaxSuccess |> json
let mergeTables (tables: floorplan_table[]) =
let status =
if mergeTables tables[0].table_number tables[1].table_number then
let outputTables = map [
"parent", tables[0];
"child", tables[1];
"merged", Model.getTable tables[0].table_number;
]
ajaxSuccess outputTables
else ajaxFail "Could Not Merge Tables"
status |> json
let unmergeTable tableNumber =
let unmerged = unmergeTable tableNumber
let unmergedTables =
match unmerged with
| Some (parent, child) ->
map ["parent", parent; "child", child] |> ajaxSuccess
| None -> ajaxFail "Could not Unmerge Table"
unmergedTables |> json
let getFloorplanData (id: int) =
let tableList = Entity.GetAllInVenue<floorplan_table>
let reservationList = getReservationList tableList
{|
tables = tableList
decorations = Entity.GetAllInVenue<floorplan_decoration>
activeTableNumbers = Model.getActiveTables (getCurrentVenue())
rooms = Entity.GetAllInVenue<floorplan_room>
reservations = reservationList
|}
|> ajaxSuccess
|> json
let transformTable (table: floorplan_table) =
Entity.Update table
|> ajaxSuccess
|> json
let createTable (tableData: floorplan_table) =
if tableExists tableData.table_number = "False" then
ajaxSuccess (addNewTable tableData)
else ajaxFail (tableExists tableData.table_number)
|> json
let deleteTable (table: floorplan_table) =
Entity.DeleteById<floorplan_table> table.id
|> ignore
table |> ajaxSuccess |> json
let transferTable (origin, destination) =
Model.transferTable origin destination
let data = map ["origin", getTable origin ; "destination", getTable destination]
ajaxSuccess data |> json
let AddDecoration (data: floorplan_decoration) =
let image = "wwwroot/images/decorations/" + data.decoration_image
let width, height = image |> GetImageSize
let aspectRatio = decimal width / decimal height
let decoration : floorplan_decoration = {
id = 0
decoration_height = (200m / aspectRatio) |> int
decoration_width = 200
decoration_rotation = 0
decoration_image = data.decoration_image
decoration_pos_x = data.decoration_pos_x
decoration_pos_y = data.decoration_pos_y
decoration_room = data.decoration_room
venue_id = data.venue_id
}
Entity.Create decoration
|> ajaxSuccess
|> json
let UpdateDecoration (data: floorplan_decoration) =
Entity.Update data
|> ignore
ajaxSuccess "true" |> json
let DeleteDecoration (decorationToDelete: floorplan_decoration) =
Entity.DeleteById<floorplan_decoration> decorationToDelete.id
|> ajaxSuccess
|> json
let loadFloorplan (ctx: HttpContext) : HttpHandler =
Authenticate.Model.RequireClerkAuthentication ctx
let roomMenu =
Entity.GetAllInVenue<floorplan_room>
|> Array.map makeRoomButton
|> joinWithNewLine
let variables = map [
"title", "Floorplan"
"roomMenu", roomMenu
"decorator", Entities.Floorplan_Decorations.Controller.generateDecorator()
]
let styles = ["dredgepos.floorplan.css"]
let scripts = ["../external/konva.min.js" ; "dredgepos.floorplan.js"]
let currentClerk = recordToMap <| Authenticate.Model.getCurrentClerk ctx
let arrays = map ["clerk", currentClerk]
htmlString <| Theme.loadTemplateWithVarsArraysScriptsAndStyles "floorplan" variables arrays scripts styles

View File

@@ -1,41 +1,12 @@
module Floorplan module DredgePos.Floorplan.Model
open DredgePos
open Reservations
let currentVenue = 1
open DredgePos.Types
open System open System
open System.IO open System.IO
open System.Xml.Linq open System.Xml.Linq
open DredgeFramework open DredgeFramework
open Dapper
open Dapper.FSharp open Dapper.FSharp
open Thoth.Json.Net open Thoth.Json.Net
open Types
let floorplan_table_decoder : Decoder<floorplan_table> =
Decode.object
(fun get ->
{
table_number = get.Required.Field "table_number" Decode.int
room_id = get.Required.Field "room_id" Decode.int
venue_id = get.Required.Field "venue_id" Decode.int
pos_x = get.Required.Field "pos_x" Decode.int
pos_y = get.Required.Field "pos_y" Decode.int
shape = get.Required.Field "shape" Decode.string
width = get.Required.Field "width" Decode.int
height = get.Required.Field "height" Decode.int
default_covers = get.Required.Field "default_covers" Decode.int
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.int
id = get.Required.Field "id" Decode.int
})
let activeTablePath = "tables/active/" let activeTablePath = "tables/active/"
let getTableFile (tableNumber: int) = let getTableFile (tableNumber: int) =
@@ -50,11 +21,11 @@ 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]
(fileName.Split "/table").[1] |> int (fileName.Split "/table")[1] |> int
else 0 else 0
let openTables = //Get a list of all open tables. let openTables () = //Get a list of all open tables.
let tableList = Directory.GetFiles(activeTablePath) let tableList = Directory.GetFiles(activeTablePath)
tableList tableList
@@ -117,12 +88,13 @@ let saveOrderToTable orderXML tableNumber =
File.WriteAllText(tableFile, tableXML) File.WriteAllText(tableFile, tableXML)
let getTable (tableNumber : int) = let getTable (tableNumber : int) =
select { let query = select {
table "floorplan_tables" table "floorplan_tables"
where (eq "table_number" tableNumber + eq "venue_id" currentVenue) where (eq "table_number" tableNumber + eq "venue_id" (getCurrentVenue()))
} }
|> db.Select<floorplan_table>
|> first let result = query |> db.Select<floorplan_table>
result |> first
let getTableById (id : int) = let getTableById (id : int) =
select { select {
@@ -138,48 +110,16 @@ let getRoom (roomId: int) =
where (eq "id" roomId) where (eq "id" roomId)
} |> db.Select<floorplan_room> |> first } |> db.Select<floorplan_room> |> first
let getRoomList (venueId: int) = let updateTablePosition (floorplanTable: floorplan_table) = Entity.Update floorplanTable
select {
table "floorplan_rooms"
where (eq "venue_id" venueId)
} |> 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
getTable tableNumber
let updateTableShape (floorplanTable: floorplan_table) =
update {
table "floorplan_tables"
set floorplanTable
where (eq "table_number" floorplanTable.table_number + eq "venue_id" currentVenue)
} |> db.Update
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 (reservation: reservation) = let createEmptyReservation (reservation: reservation) =
update { update {
table "floorplan_tables" table "floorplan_tables"
set {| status = 2 |} set {| status = 2 |}
where(eq "id" reservation.reservation_table_id) where(eq "id" reservation.floorplan_table_id)
} |> db.Update |> ignore } |> db.Update |> ignore
insert{ Entity.Create reservation
table "reservations"
value reservation
} |> db.InsertOutput |> first
let getChildTables tableNumber = let getChildTables tableNumber =
let table = getTable tableNumber let table = getTable tableNumber
@@ -213,15 +153,13 @@ let tableExists (tableNumber: int) =
let numberOfResults = let numberOfResults =
select{ select{
table "floorplan_tables" table "floorplan_tables"
where (eq "table_number" tableNumber + eq "venue_id" currentVenue) where (eq "table_number" tableNumber + eq "venue_id" (getCurrentVenue()))
} |> db.Select<floorplan_table> |> length } |> db.Select<floorplan_table> |> length
match numberOfResults with match numberOfResults with
| 0 -> | 0 ->
let allTables = let allTables =
select { Entity.GetAllInVenue<floorplan_table>
table "floorplan_tables"
} |> db.Select<floorplan_table>
|> Array.map(findChildTable tableNumber) |> Array.map(findChildTable tableNumber)
|> Array.filter(fun tableNumber -> tableNumber <> 0) |> Array.filter(fun tableNumber -> tableNumber <> 0)
@@ -229,7 +167,7 @@ let tableExists (tableNumber: int) =
match allTables.Length with match allTables.Length with
| 0 -> false |> string //Table does not exist | 0 -> false |> string //Table does not exist
| _ -> | _ ->
let parentTableData = getTable allTables.[0] let parentTableData = getTable allTables[0]
let parentRoom = getRoom parentTableData.room_id let parentRoom = getRoom parentTableData.room_id
let parentRoomName = parentRoom.room_name let parentRoomName = parentRoom.room_name
language.getAndReplace "error_table_exists_merged" [parentRoomName; parentTableData.table_number.ToString()] language.getAndReplace "error_table_exists_merged" [parentRoomName; parentTableData.table_number.ToString()]
@@ -248,21 +186,7 @@ let addNewTableWithoutOutput (newTable: floorplan_table) =
} }
|> db.Insert |> db.Insert
let addNewTable (newTable: floorplan_table) = let addNewTable (newTable: floorplan_table) = Entity.Create newTable
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)
} |> db.Delete |> ignore
let mergeTables parent child = //Merge two tables together let mergeTables parent child = //Merge two tables together
if parent = child then false else if parent = child then false else
@@ -292,13 +216,12 @@ let mergeTables parent child = //Merge two tables together
let existingChildrenJson = parentTable.merged_children |> StringTrim let existingChildrenJson = parentTable.merged_children |> StringTrim
let existingChildren = let existingChildren =
existingChildrenJson existingChildrenJson |> Decode.Auto.fromString<floorplan_table[]>
|> Decode.fromString(Decode.list floorplan_table_decoder)
let tableList = let tableList =
match existingChildren with match existingChildren with
| Error _ -> [newChildTable] | Error _ -> [|newChildTable|]
| Ok tables -> tables @ [newChildTable] | Ok tables -> [tables ; [|newChildTable|]] |> Array.concat
let newChildrenJson = tableList |> jsonEncode let newChildrenJson = tableList |> jsonEncode
let parentPreviousState = parentTable |> jsonEncode let parentPreviousState = parentTable |> jsonEncode
@@ -314,10 +237,11 @@ let mergeTables parent child = //Merge two tables together
pos_y = newPosY pos_y = newPosY
default_covers = parentTable.default_covers + childTable.default_covers default_covers = parentTable.default_covers + childTable.default_covers
|} |}
where (eq "table_number" parent + eq "venue_id" currentVenue) where (eq "table_number" parent + eq "venue_id" (getCurrentVenue()))
} |> db.Update |> ignore } |> db.Update |> ignore
deleteTable child Entity.DeleteById<floorplan_table> newChildTable.id
|> ignore
true true
@@ -326,7 +250,7 @@ let updateUnmergedTables parentTable childTable =
update { update {
table "floorplan_tables" table "floorplan_tables"
set parentTable set parentTable
where(eq "table_number" parentTable.table_number + eq "venue_id" currentVenue) where(eq "table_number" parentTable.table_number + eq "venue_id" (getCurrentVenue()))
} |> db.Update |> ignore } |> db.Update |> ignore
addNewTableWithoutOutput childTable |> ignore addNewTableWithoutOutput childTable |> ignore
@@ -350,44 +274,22 @@ let unmergeTable tableNumber = //Separates a merged table into itself and the la
Some (getTable currentTable.table_number, unmergedChild) Some (getTable currentTable.table_number, unmergedChild)
| Error _ -> None | Error _ -> None
let convertRoomListToLinks (room: floorplan_room) =
let vars = map [
"roomId", room.id |> string
"roomName", room.room_name
]
Theme.loadTemplateWithVars "roomButton" vars
let getReservationList (tableList: floorplan_table[]) = let getReservationList (tableList: floorplan_table[]) =
let tableIds = tableList |> Array.collect Entity.GetAllRelated<reservation, floorplan_table>
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 = {
id = 0 id = 0
reservation_name = name name = name
reservation_time = time time = time
reservation_covers = covers covers = covers
reservation_table_id = 0 floorplan_table_id = 0
reservation_created_at = CurrentTime() created_at = CurrentTime()
} }
insert { Entity.Create reservation
table "reservations"
value reservation
} |> db.Insert
let tableList venueId = let tableList () = Entity.GetAllInVenue<floorplan_table>
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

24
Floorplan/Router.fs Normal file
View File

@@ -0,0 +1,24 @@
module DredgePos.Floorplan.Router
open DredgePos
open DredgePos.Types
open Saturn
open Giraffe
let floorplan = (warbler (fun ctx -> DredgePos.Floorplan.Controller.loadFloorplan (snd ctx)))
let router = router {
pipe_through Ajax.Router.pipeline
get "/" floorplan
get "" floorplan
post "/mergeTables" (bindJson<floorplan_table[]> Controller.mergeTables)
post "/transformTable" (bindJson<floorplan_table> Controller.transformTable)
post "/createTable" (bindJson<floorplan_table> Controller.createTable)
post "/addDecoration" (bindJson<floorplan_decoration> Controller.AddDecoration)
post "/updateDecoration" (bindJson<floorplan_decoration> Controller.UpdateDecoration)
post "/deleteDecoration" (bindJson<floorplan_decoration> Controller.DeleteDecoration)
post "/deleteTable" (bindJson<floorplan_table> Controller.deleteTable)
getf "/getFloorplanData/%i" Controller.getFloorplanData
getf "/transferTable/%i/%i" Controller.transferTable
getf "/unmergeTable/%i" Controller.unmergeTable
}

View File

@@ -1,26 +0,0 @@
module Entity
open DredgePos
open Types
open Dapper.FSharp
open DredgeFramework
let getDatabaseTable (record: 'a) = record.GetType().ToString().ToLower() + "s"
let addToDatabase (record: 'x)=
let tableName = getDatabaseTable record
insert {
table tableName
value record
}
|> db.InsertOutput
|> first
let updateInDatabase (record: 'x) =
let tableName = getDatabaseTable record
(* Run an update query *)
update {
table tableName
set record
}
|> db.Update |> ignore
record

89
OrderScreen/Controller.fs Normal file
View File

@@ -0,0 +1,89 @@
module DredgePos.OrderScreen.Controller
open DredgePos
open DredgeFramework
open DredgePos.Types
open Giraffe
open Microsoft.AspNetCore.Http
let getOrderScreenData (tableNumber: int) =
{|
order_screen_pages = Entity.GetAllInVenue<order_screen_page_group>
sales_categories = Entity.GetAllInVenue<sales_category>
print_groups = Entity.GetAllInVenue<print_group>
custom_item = Entity.GetAllByColumn<item> "item_code" "OPEN000" |> first
table = Floorplan.Model.getTable tableNumber
|}
|> ajaxSuccess
|> json
let loadGrid (gridId: int) =
let grid = Entity.GetById<grid> gridId
let gridHtml = Model.loadGrid gridId
if gridHtml = "Error" then ajaxFail gridHtml
else ajaxSuccess {|grid=grid;gridHtml=gridHtml|}
|> json
let loadOrderScreen (ctx: HttpContext) (tableNumber: int) : HttpHandler =
Authenticate.Model.RequireClerkAuthentication ctx
let table = Floorplan.Model.getTable tableNumber
let covers = if tableNumber > 0 then table.default_covers else 0
let coverString = language.getAndReplace "covers" [covers]
let changeCoverNumberButton = if tableNumber > 0 then Theme.loadTemplateWithVars "orderScreen/change_cover_number_button" (map ["covers", coverString]) else ""
let orderNumber =
if tableNumber > 0 then language.getAndReplace "active_table" [tableNumber]
else language.get "new_order"
let containerAttributes =
if tableNumber > 0 then
map ["data-table", jsonEncode table]
|> Theme.htmlAttributes
else ""
let categoryList =
Entity.GetAllInVenue<order_screen_page_group>
|> Array.filter (fun page_group -> page_group.id <> 0)
|> Array.sortBy (fun {order=order} -> order)
|> Array.map (fun category ->
let categoryMap = recordToMap category
let categoryArray = map ["page", categoryMap]
Theme.loadTemplateWithArrays "orderScreen/page_group_button" categoryArray
)
|> joinWithNewLine
let grids =
Model.getAllPageGrids ()
|> Array.map Model.getPagesHTML
|> joinWithNewLine
let coverSelectorButtons =
Array.init (covers+1) id
|> Array.map(fun coverNumber ->
let text = if coverNumber > 0 then language.getAndReplace "selected_cover" [coverNumber]
else language.get "cover_zero"
Theme.PosButton text "coverSelectorButton" $"""data-cover="{coverNumber}" """)
|> String.concat "\n"
let variables = map [
"title", "Order"
"containerAttributes", containerAttributes
"categoryList", categoryList
"pageGroups", grids
"orderNumber", orderNumber
"changeCoverNumberButton", changeCoverNumberButton
"covers", coverString
"salesCategoryOverrideButtons", Model.generateSalesCategoryOverrideButtons ()
"coverSelectorButtons", coverSelectorButtons
]
let styles = ["dredgepos.orderScreen.css"]
let scripts = ["dredgepos.tables.js";"../external/currency.min.js";"dredgepos.orderScreen.js"; ]
let currentClerk = recordToMap <| Authenticate.Model.getCurrentClerk ctx
let arrays = map ["clerk", currentClerk]
Theme.loadTemplateWithVarsArraysScriptsAndStyles "orderScreen" variables arrays scripts styles
|> htmlString

136
OrderScreen/Model.fs Normal file
View File

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

15
OrderScreen/Router.fs Normal file
View File

@@ -0,0 +1,15 @@
module DredgePos.OrderScreen.Router
open DredgePos
open DredgePos.Types
open Saturn
open Giraffe
let router = router {
pipe_through Ajax.Router.pipeline
getf "/getOrderScreenData/%i" Controller.getOrderScreenData
getf "/getGridHtml/%i" Controller.loadGrid
post "/updateCovers" (bindJson<floorplan_table> (fun table -> Entity.Update table |> Array.head |> DredgeFramework.ajaxSuccess |> json))
get "/" (warbler (fun ctx -> Controller.loadOrderScreen (snd ctx) 0))
getf "/%i" (fun number -> (warbler (fun ctx -> Controller.loadOrderScreen (snd ctx) number)))
}

View File

@@ -1,54 +0,0 @@
module PageController
open Microsoft.AspNetCore.Http
open Floorplan
open Giraffe
open DredgeFramework
let loadHomePage(): HttpHandler =
let variables = map["title", "Log In"]
let scripts = ["dredgepos.authenticate.js"]
let styles = ["dredgepos.authenticate.css"]
htmlString <| Theme.loadTemplateWithVarsScriptsAndStyles "authenticate" variables scripts styles
let loadFloorplan (ctx: HttpContext) : HttpHandler =
Session.RequireClerkAuthentication ctx
let roomMenu =
getRoomList currentVenue
|> Array.map convertRoomListToLinks
|> String.concat "\n"
let variables = map [
"title", "Floorplan"
"roomMenu", roomMenu
"decorator", Decorations.generateDecorator()
]
let styles = ["dredgepos.floorplan.css"]
let scripts = ["external/konva.min.js" ; "dredgepos.floorplan.js"]
let currentClerk = recordToMap <| Session.getCurrentClerk ctx
let arrays = map["clerk", currentClerk]
htmlString <| Theme.loadTemplateWithVarsArraysScriptsAndStyles "floorplan" variables arrays scripts styles
let loadContactPage id =
Session.clerkLogin 1408 |> ignore
Theme.loadTemplate "index"
let getOpenTables() =
let rows = Floorplan.openTables
rows |> jsonEncode
let transferTables() =
Theme.loadTemplate "index"
let mergeTables parent child =
Floorplan.mergeTables parent child |> ignore
"done"
let unmergeTables table =
Floorplan.unmergeTable table |> ignore
"done"

2
Printer.module.fs Normal file
View File

@@ -0,0 +1,2 @@
module Printer

View File

@@ -1,62 +1,25 @@
namespace WebApplication namespace DredgePos
open DredgePos open DredgePos
open Microsoft.AspNetCore.Server.Kestrel.Core
open Reservations
open Saturn open Saturn
open Giraffe open Giraffe
open Types
module Program = module Program =
let router = router {
let handlePostRoute<'a> handlerFunction post next ctx = pipe_through Ajax.Router.pipeline
json (handlerFunction ctx post) next ctx
let browser = pipeline {
use_warbler
}
let ajaxRouter = router {
pipe_through browser
post "/authenticateClerk" (bindJson<int> (handlePostRoute AjaxController.loginWithLoginCode) )
post "/getTableData" (bindJson<int> AjaxController.getTableData)
post "/transformTable" (bindJson<floorplan_table> AjaxController.transformTable)
post "/createTable" (bindJson<floorplan_table> AjaxController.createTable)
post "/addDecoration" (bindJson<floorplan_decoration> AjaxController.AddDecoration)
post "/updateDecoration" (bindJson<floorplan_decoration> AjaxController.UpdateDecoration)
post "/deleteDecoration" (bindJson<floorplan_decoration> AjaxController.DeleteDecoration)
post "/deleteTable" (bindJson<floorplan_table> AjaxController.deleteTable)
post "/mergeTables" (bindJson<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<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 "/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)
}
let pageRouter = router {
pipe_through browser
not_found_handler (setStatusCode 404 >=> text "404") not_found_handler (setStatusCode 404 >=> text "404")
get "/" (redirectTo true "/login") get "/" (redirectTo true "/login")
get "/login" (warbler (fun _ -> PageController.loadHomePage() )) forward "/ajax" Ajax.Router.router
get "/floorplan" (warbler (fun ctx -> PageController.loadFloorplan (snd ctx))) forward "/floorplan" DredgePos.Floorplan.Router.router
forward "/ajax" ajaxRouter forward "/order" DredgePos.OrderScreen.Router.router
forward "/login" DredgePos.Authenticate.Router.router
forward "/reservations" DredgePos.Reservations.Router.router
} }
let app = application { let app = application {
use_mime_types [(".woff", "application/font-woff")]
use_static "wwwroot" use_static "wwwroot"
use_router pageRouter use_router router
url "http://0.0.0.0:5001" url "http://0.0.0.0:5001"
} }

View File

@@ -0,0 +1,29 @@
module DredgePos.Reservations.Controller
open DredgeFramework
open DredgePos
open DredgePos.Types
open Giraffe
let newEmptyReservation (reservation: reservation) =
let newReservation = {reservation with
created_at = CurrentTime()
time = CurrentTime()
}
if reservation.floorplan_table_id > 0 then
let table = {(Entity.GetById<floorplan_table> reservation.floorplan_table_id) with
status = 2
default_covers = reservation.covers}
Floorplan.Model.updateTablePosition table |> ignore
let createdReservation = Floorplan.Model.createEmptyReservation newReservation
ajaxSuccess createdReservation |> json
let updateReservation (reservation: reservation) = Model.updateReservation reservation |> ajaxSuccess |> json
let unreserveTable (table: floorplan_table) =
let newTable = {table with status = 0}
Floorplan.Model.updateTablePosition newTable |> ignore
Model.DeleteReservation newTable.id
newTable |> ajaxSuccess |> json

View File

@@ -1,19 +1,10 @@
module Reservations module DredgePos.Reservations.Model
open System
open DredgeFramework open DredgeFramework
open Dapper.FSharp open Dapper.FSharp
open DredgePos open DredgePos
open Types open Types
let GetReservationById (id: int) =
select {
table "reservations"
where (eq "id" id)
}
|> db.Select<reservation>
|> first
let updateReservation (reservation: reservation) = let updateReservation (reservation: reservation) =
update{ update{
table "reservations" table "reservations"
@@ -25,5 +16,5 @@ let updateReservation (reservation: reservation) =
let DeleteReservation (tableId: int) = let DeleteReservation (tableId: int) =
delete { delete {
table "reservations" table "reservations"
where (eq "reservation_table_id" tableId) where (eq "floorplan_table_id" tableId)
} |> db.Delete |> ignore } |> db.Delete |> ignore

13
Reservations/Router.fs Normal file
View File

@@ -0,0 +1,13 @@
module DredgePos.Reservations.Router
open DredgePos
open DredgePos.Types
open Saturn
open Giraffe
let router = router {
pipe_through Ajax.Router.pipeline
post "/newEmptyReservation" (bindJson<reservation> Controller.newEmptyReservation)
post "/updateReservation" (bindJson<reservation> Controller.updateReservation)
post "/unreserveTable" (bindJson<floorplan_table> Controller.unreserveTable )
}

View File

@@ -1,55 +0,0 @@
module DredgePos.Types
[<CLIMutable>]
type reservation = {
id: int
reservation_name: string
reservation_time: int
reservation_covers: int
reservation_table_id: int
reservation_created_at: int
}
[<CLIMutable>]
type floorplan_table = {
table_number: int
room_id: int
venue_id: int
pos_x: int
pos_y: int
shape: string
width: int
height: int
default_covers: int
rotation: int
merged_children: string
previous_state: string
status: int
id: int
}
[<CLIMutable>]
type floorplan_room = {
id: int
room_name: string
background_image: string
venue_id: int
}
[<CLIMutable>]
type floorplan_decoration = {
id: int
decoration_room: int
decoration_pos_x: int
decoration_pos_y: int
decoration_rotation: int
decoration_width: int
decoration_height: int
decoration_image: string
}
[<CLIMutable>]
type clerk = {id: int; clerk_name: string; clerk_login_code: int; clerk_usergroup: int}
[<CLIMutable>]
type session = {id: int; session_id: string; clerk_json: string; clerk_id: int; expires: int}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

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