aboutsummaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/migrations/1.sql65
-rw-r--r--server/src/Design/Global.hs26
-rw-r--r--server/src/Design/Helper.hs29
-rw-r--r--server/src/Design/View/Header.hs8
-rw-r--r--server/src/Design/View/Payment/Header.hs34
-rw-r--r--server/src/Job/Model.hs14
6 files changed, 121 insertions, 55 deletions
diff --git a/server/migrations/1.sql b/server/migrations/1.sql
new file mode 100644
index 0000000..d7c300e
--- /dev/null
+++ b/server/migrations/1.sql
@@ -0,0 +1,65 @@
+CREATE TABLE IF NOT EXISTS "user" (
+ "id" INTEGER PRIMARY KEY,
+ "creation" TIMESTAMP NOT NULL,
+ "email" VARCHAR NOT NULL,
+ "name" VARCHAR NOT NULL,
+ CONSTRAINT "uniq_user_email" UNIQUE ("email"),
+ CONSTRAINT "uniq_user_name" UNIQUE ("name")
+);
+
+CREATE TABLE IF NOT EXISTS "job" (
+ "id" INTEGER PRIMARY KEY,
+ "kind" VARCHAR NOT NULL,
+ "last_execution" TIMESTAMP NULL,
+ "last_check" TIMESTAMP NULL,
+ CONSTRAINT "uniq_job_kind" UNIQUE ("kind")
+);
+
+CREATE TABLE IF NOT EXISTS "sign_in"(
+ "id" INTEGER PRIMARY KEY,
+ "token" VARCHAR NOT NULL,
+ "creation" TIMESTAMP NOT NULL,
+ "email" VARCHAR NOT NULL,
+ "is_used" BOOLEAN NOT NULL,
+ CONSTRAINT "uniq_sign_in_token" UNIQUE ("token")
+);
+
+CREATE TABLE IF NOT EXISTS "payment"(
+ "id" INTEGER PRIMARY KEY,
+ "user_id" INTEGER NOT NULL REFERENCES "user",
+ "name" VARCHAR NOT NULL,
+ "cost" INTEGER NOT NULL,
+ "date" DATE NOT NULL,
+ "frequency" VARCHAR NOT NULL,
+ "created_at" TIMESTAMP NOT NULL,
+ "edited_at" TIMESTAMP NULL,
+ "deleted_at" TIMESTAMP NULL
+);
+
+CREATE TABLE IF NOT EXISTS "income"(
+ "id" INTEGER PRIMARY KEY,
+ "user_id" INTEGER NOT NULL REFERENCES "user",
+ "date" DATE NOT NULL,
+ "amount" INTEGERNOT NULL,
+ "created_at" TIMESTAMP NOT NULL,
+ "edited_at" TIMESTAMP NULL,
+ "deleted_at" TIMESTAMP NULL
+);
+
+CREATE TABLE IF NOT EXISTS "category"(
+ "id" INTEGER PRIMARY KEY,
+ "name" VARCHAR NOT NULL,
+ "color" VARCHAR NOT NULL,
+ "created_at" TIMESTAMP NOT NULL,
+ "edited_at" TIMESTAMP NULL,
+ "deleted_at" TIMESTAMP NULL
+);
+
+CREATE TABLE IF NOT EXISTS "payment_category"(
+ "id" INTEGER PRIMARY KEY,
+ "name" VARCHAR NOT NULL,
+ "category" INTEGER NOT NULL REFERENCES "category",
+ "created_at" TIMESTAMP NOT NULL,
+ "edited_at" TIMESTAMP NULL,
+ CONSTRAINT "uniq_payment_category_name" UNIQUE ("name")
+);
diff --git a/server/src/Design/Global.hs b/server/src/Design/Global.hs
index 34d772e..5e5035c 100644
--- a/server/src/Design/Global.hs
+++ b/server/src/Design/Global.hs
@@ -71,3 +71,29 @@ global = do
".undo" & Helper.button Color.silver Color.white (px Constants.inputHeight) Constants.focusLighten
svg ? height (pct 100)
+
+ button ? do
+ ".content" ? display flex
+ svg # ".loader" ? display none
+
+ ".waiting" & do
+ ".content" ? do
+ display none
+ svg # ".loader" ? do
+ display block
+ rotateKeyframes
+ rotateAnimation
+
+rotateAnimation :: Css
+rotateAnimation = do
+ animationName "rotate"
+ animationDuration (sec 1)
+ animationTimingFunction easeOut
+ animationIterationCount infinite
+
+rotateKeyframes :: Css
+rotateKeyframes = keyframes
+ "rotate"
+ [ (0, "transform" -: "rotate(0deg)")
+ , (100, "transform" -: "rotate(360deg)")
+ ]
diff --git a/server/src/Design/Helper.hs b/server/src/Design/Helper.hs
index 89f5958..6980c71 100644
--- a/server/src/Design/Helper.hs
+++ b/server/src/Design/Helper.hs
@@ -1,7 +1,6 @@
module Design.Helper
( clearFix
, button
- , waitable
, input
, centeredWithMargin
, verticalCentering
@@ -37,20 +36,6 @@ button backgroundCol textCol h focusOp = do
textAlign (alignSide sideCenter)
hover & backgroundColor (focusOp backgroundCol)
focus & backgroundColor (focusOp backgroundCol)
- waitable
-
-waitable :: Css
-waitable = do
- ".content" ? display flex
- svg # ".loader" ? display none
-
- ".waiting" & do
- ".content" ? do
- display none
- svg # ".loader" ? do
- display block
- rotateKeyframes
- rotateAnimation
input :: Double -> Css
input h = do
@@ -72,17 +57,3 @@ verticalCentering = do
position absolute
top (pct 50)
"transform" -: "translateY(-50%)"
-
-rotateAnimation :: Css
-rotateAnimation = do
- animationName "rotate"
- animationDuration (sec 1)
- animationTimingFunction easeOut
- animationIterationCount infinite
-
-rotateKeyframes :: Css
-rotateKeyframes = keyframes
- "rotate"
- [ (0, "transform" -: "rotate(0deg)")
- , (100, "transform" -: "rotate(360deg)")
- ]
diff --git a/server/src/Design/View/Header.hs b/server/src/Design/View/Header.hs
index 904a2f5..97f1802 100644
--- a/server/src/Design/View/Header.hs
+++ b/server/src/Design/View/Header.hs
@@ -2,13 +2,12 @@ module Design.View.Header
( design
) where
-import Data.Monoid ((<>))
+import Data.Monoid ((<>))
import Clay
-import Design.Color as Color
-import qualified Design.Helper as Helper
-import qualified Design.Media as Media
+import Design.Color as Color
+import qualified Design.Media as Media
design :: Css
design = do
@@ -56,7 +55,6 @@ design = do
Media.tabletDesktop $ headerPadding
".signOut" ? do
- Helper.waitable
display flex
svg ? do
Media.tabletDesktop $ width (px 30)
diff --git a/server/src/Design/View/Payment/Header.hs b/server/src/Design/View/Payment/Header.hs
index 36bc8d9..80c5436 100644
--- a/server/src/Design/View/Payment/Header.hs
+++ b/server/src/Design/View/Payment/Header.hs
@@ -50,22 +50,24 @@ design = do
".searchLine" ? do
marginBottom (em 1)
- form ? do
- Media.mobile $ textAlign (alignSide sideCenter)
-
- ".textInput" ? do
- display inlineBlock
- marginBottom (px 0)
-
- Media.tabletDesktop $ marginRight (px 30)
- Media.mobile $ do
- marginBottom (em 1)
- width (pct 100)
-
- ".radioGroup" ? do
- display inlineBlock
- marginBottom (px 0)
- ".title" ? display none
+ Media.mobile $ textAlign (alignSide sideCenter)
+
+ ".textInput" ? do
+ display inlineBlock
+ marginBottom (px 0)
+ button ? do
+ svg ? "path" ? ("fill" -: Color.toString Color.silver)
+ hover & svg ? "path" ? ("fill" -: Color.toString (Color.silver -. 25))
+
+ Media.tabletDesktop $ marginRight (px 30)
+ Media.mobile $ do
+ marginBottom (em 1)
+ width (pct 100)
+
+ ".radioGroup" ? do
+ display inlineBlock
+ marginBottom (px 0)
+ ".title" ? display none
".infos" ? do
Media.tabletDesktop $ lineHeight (px Constants.inputHeight)
diff --git a/server/src/Job/Model.hs b/server/src/Job/Model.hs
index a5fa62b..1dd6c63 100644
--- a/server/src/Job/Model.hs
+++ b/server/src/Job/Model.hs
@@ -5,7 +5,6 @@ module Job.Model
, actualizeLastCheck
) where
-import Data.Maybe (isJust)
import Data.Time.Clock (UTCTime, getCurrentTime)
import Database.SQLite.Simple (Only (Only))
import qualified Database.SQLite.Simple as SQLite
@@ -24,15 +23,20 @@ data Job = Job
getLastExecution :: Kind -> Query (Maybe UTCTime)
getLastExecution jobKind =
Query (\conn -> do
- [Only time] <- SQLite.query conn "SELECT last_execution FROM job WHERE kind = ?" (Only jobKind) :: IO [Only (Maybe UTCTime)]
- return time
+ result <- SQLite.query conn "SELECT last_execution FROM job WHERE kind = ?" (Only jobKind) :: IO [Only UTCTime]
+ return $ case result of
+ [Only time] -> Just time
+ _ -> Nothing
)
actualizeLastExecution :: Kind -> UTCTime -> Query ()
actualizeLastExecution jobKind time =
Query (\conn -> do
- [Only result] <- SQLite.query conn "SELECT 1 FROM job WHERE kind = ?" (Only jobKind) :: IO [Only (Maybe Int)]
- if isJust result
+ result <- SQLite.query conn "SELECT 1 FROM job WHERE kind = ?" (Only jobKind) :: IO [Only Int]
+ let hasJob = case result of
+ [Only _] -> True
+ _ -> False
+ if hasJob
then SQLite.execute conn "UPDATE job SET last_execution = ? WHERE kind = ?" (time, jobKind)
else SQLite.execute conn "INSERT INTO job (kind, last_execution, last_check) VALUES (?, ?, ?)" (jobKind, time, time)
)