forked from Kispi/Core
feat(core): add employer portal
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
a2994e50e6
commit
c70dba5ab3
20 changed files with 625 additions and 106 deletions
12
.drone.yml
12
.drone.yml
|
@ -6,19 +6,25 @@ steps:
|
|||
image: node:lts-alpine
|
||||
commands:
|
||||
- cd webapp
|
||||
- corepack pnpm@8.6.0 install
|
||||
- corepack pnpm@8.6.6 install
|
||||
|
||||
- name: lint-webapp
|
||||
image: node:lts-alpine
|
||||
commands:
|
||||
- cd webapp
|
||||
- corepack pnpm@8.6.0 lint
|
||||
- corepack pnpm@8.6.6 lint
|
||||
|
||||
- name: version-webapp
|
||||
image: node:lts-alpine
|
||||
commands:
|
||||
- cd webapp
|
||||
- corepack pnpm@8.6.6 generate-version
|
||||
|
||||
- name: build-webapp
|
||||
image: node:lts-alpine
|
||||
commands:
|
||||
- cd webapp
|
||||
- corepack pnpm@8.6.0 build
|
||||
- corepack pnpm@8.6.6 build
|
||||
|
||||
- name: deploy
|
||||
image: plugins/docker
|
||||
|
|
|
@ -5,7 +5,7 @@ go 1.20
|
|||
require (
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198
|
||||
github.com/pocketbase/pocketbase v0.16.6
|
||||
github.com/pocketbase/pocketbase v0.16.8
|
||||
github.com/pterm/pterm v0.12.62
|
||||
)
|
||||
|
||||
|
@ -15,7 +15,7 @@ require (
|
|||
atomicgo.dev/schedule v0.0.2 // indirect
|
||||
github.com/AlecAivazis/survey/v2 v2.3.7 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.294 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.298 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.18.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.27 // indirect
|
||||
|
@ -48,7 +48,7 @@ require (
|
|||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/google/wire v0.5.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.11.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
|
||||
github.com/gookit/color v1.5.3 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
|
@ -70,21 +70,21 @@ require (
|
|||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
gocloud.dev v0.30.0 // indirect
|
||||
golang.org/x/crypto v0.10.0 // indirect
|
||||
golang.org/x/image v0.8.0 // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/net v0.11.0 // indirect
|
||||
golang.org/x/oauth2 v0.9.0 // indirect
|
||||
golang.org/x/sys v0.9.0 // indirect
|
||||
golang.org/x/term v0.9.0 // indirect
|
||||
golang.org/x/text v0.10.0 // indirect
|
||||
golang.org/x/crypto v0.11.0 // indirect
|
||||
golang.org/x/image v0.9.0 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/net v0.12.0 // indirect
|
||||
golang.org/x/oauth2 v0.10.0 // indirect
|
||||
golang.org/x/sys v0.10.0 // indirect
|
||||
golang.org/x/term v0.10.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.10.0 // indirect
|
||||
golang.org/x/tools v0.11.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/api v0.129.0 // indirect
|
||||
google.golang.org/api v0.130.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529 // indirect
|
||||
google.golang.org/grpc v1.56.1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 // indirect
|
||||
google.golang.org/grpc v1.56.2 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
lukechampine.com/uint128 v1.3.0 // indirect
|
||||
modernc.org/cc/v3 v3.41.0 // indirect
|
||||
|
|
|
@ -187,6 +187,7 @@ cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IK
|
|||
cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI=
|
||||
cloud.google.com/go/compute v1.20.0 h1:cUOcywWuowO9It2i1KX1lIb0HH7gLv6nENKuZGnlcSo=
|
||||
cloud.google.com/go/compute v1.20.0/go.mod h1:kn5BhC++qUWR/AM3Dn21myV7QbgqejW04cAOrtppaQI=
|
||||
cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg=
|
||||
cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=
|
||||
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
|
||||
|
@ -791,6 +792,8 @@ github.com/aws/aws-sdk-go v1.44.245/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8
|
|||
github.com/aws/aws-sdk-go v1.44.284/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go v1.44.294 h1:3x7GaEth+pDU9HwFcAU0awZlEix5CEdyIZvV08SlHa8=
|
||||
github.com/aws/aws-sdk-go v1.44.294/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go v1.44.298 h1:5qTxdubgV7PptZJmp/2qDwD2JL187ePL7VOxsSh1i3g=
|
||||
github.com/aws/aws-sdk-go v1.44.298/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
|
||||
github.com/aws/aws-sdk-go-v2 v1.18.1 h1:+tefE750oAb7ZQGzla6bLkOwfcQCEtC5y2RqoqCeqKo=
|
||||
github.com/aws/aws-sdk-go-v2 v1.18.1/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
|
||||
|
@ -1300,6 +1303,7 @@ github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
|
|||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
|
@ -1451,6 +1455,8 @@ github.com/googleapis/gax-go/v2 v2.9.1/go.mod h1:4FG3gMrVZlyMp5itSYKMU9z/lBE7+Sb
|
|||
github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw=
|
||||
github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4=
|
||||
github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
|
||||
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
|
||||
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
|
||||
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
||||
|
@ -1933,6 +1939,8 @@ github.com/pocketbase/dbx v1.10.0 h1:58VIT7r6T+BnVbYVosvGBsPjQEic3/VFRYGT823vWSQ
|
|||
github.com/pocketbase/dbx v1.10.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
|
||||
github.com/pocketbase/pocketbase v0.16.6 h1:zE+9SPXlhimZpuiD4KrmY+cp4b2lyL8gLAbkjj5YqFY=
|
||||
github.com/pocketbase/pocketbase v0.16.6/go.mod h1:xXXL26RVy0vGxDHOffoaeEv7CvZSJHivnfAeygmEfD8=
|
||||
github.com/pocketbase/pocketbase v0.16.8 h1:uILzBla2DNMFGZFRu0cStIv3AVjYgicOQs2F1AeXpGw=
|
||||
github.com/pocketbase/pocketbase v0.16.8/go.mod h1:vmajDvROzq//BiQ4RoNqHmjHf5i8RMgK665zQ14oo/g=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
|
@ -2345,6 +2353,8 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU
|
|||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
@ -2379,6 +2389,8 @@ golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeap
|
|||
golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/image v0.8.0 h1:agUcRXV/+w6L9ryntYYsF2x9fQTMd4T8fiiYXAVW6Jg=
|
||||
golang.org/x/image v0.8.0/go.mod h1:PwLxp3opCYg4WR2WO9P0L6ESnsD6bLTWcw8zanLMVFM=
|
||||
golang.org/x/image v0.9.0 h1:QrzfX26snvCM20hIhBwuHI/ThTg18b/+kcKdXHvnR+g=
|
||||
golang.org/x/image v0.9.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
@ -2413,6 +2425,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -2509,6 +2523,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
|||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
|
||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -2544,6 +2560,8 @@ golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4
|
|||
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
||||
golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs=
|
||||
golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw=
|
||||
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
|
||||
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -2723,6 +2741,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
@ -2738,6 +2758,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
|||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
|
||||
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -2756,6 +2778,8 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -2864,6 +2888,8 @@ golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
|||
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
||||
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||
golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8=
|
||||
golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -2954,6 +2980,8 @@ google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvy
|
|||
google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750=
|
||||
google.golang.org/api v0.129.0 h1:2XbdjjNfFPXQyufzQVwPf1RRnHH8Den2pfNE2jw7L8w=
|
||||
google.golang.org/api v0.129.0/go.mod h1:dFjiXlanKwWE3612X97llhsoI36FAoIiRj3aTl5b/zE=
|
||||
google.golang.org/api v0.130.0 h1:A50ujooa1h9iizvfzA4rrJr2B7uRmWexwbekQ2+5FPQ=
|
||||
google.golang.org/api v0.130.0/go.mod h1:J/LCJMYSDFvAVREGCbrESb53n4++NMBDetSHGL5I5RY=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
@ -3126,6 +3154,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529 h1:DEH99RbiLZhMxrpEJCZ0A+wdTe0EOgou/poSLx9vWf4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 h1:2FZP5XuJY9zQyGM5N0rtovnoXjiMUEIUMvw0m9wlpLc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o=
|
||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
|
@ -3176,6 +3206,8 @@ google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGO
|
|||
google.golang.org/grpc v1.56.0/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ=
|
||||
google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI=
|
||||
google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
|
|
2
webapp/.env.example
Normal file
2
webapp/.env.example
Normal file
|
@ -0,0 +1,2 @@
|
|||
# The app version is dynamically set by the build script
|
||||
VITE_APP_VERSION="dev"
|
|
@ -9,13 +9,14 @@
|
|||
"lint": "eslint -c .eslintrc.js src/",
|
||||
"preview": "vite preview",
|
||||
"typegen": "pocketbase-typegen --json ../server/pb_schema.json --out ./src/types/pocketbase.types.ts",
|
||||
"optimize-svg": "svgo -f ./src/assets/svg/ --config=./src/assets/svg/svgo.config.js"
|
||||
"optimize-svg": "svgo -f ./src/assets/svg/ --config=./src/assets/svg/svgo.config.js",
|
||||
"generate-version": "node ./scripts/generate-version.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroicons/vue": "^2.0.18",
|
||||
"@vueuse/core": "^10.2.1",
|
||||
"canvas-confetti": "^1.6.0",
|
||||
"daisyui": "^3.1.9",
|
||||
"daisyui": "^3.2.1",
|
||||
"pocketbase": "^0.15.2",
|
||||
"vue": "^3.3.4",
|
||||
"vue-router": "4.2.4"
|
||||
|
@ -32,13 +33,14 @@
|
|||
"eslint-plugin-tailwindcss": "^3.13.0",
|
||||
"eslint-plugin-vue": "^9.15.1",
|
||||
"eslint-plugin-vue-scoped-css": "^2.5.0",
|
||||
"git-commit-info": "^2.0.2",
|
||||
"pocketbase-typegen": "^1.1.11",
|
||||
"postcss": "^8.4.25",
|
||||
"sass": "^1.63.6",
|
||||
"svgo": "^3.0.2",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"typescript": "^5.1.6",
|
||||
"vite": "^4.4.1",
|
||||
"vite": "^4.4.2",
|
||||
"vue-eslint-parser": "^9.3.1",
|
||||
"vue-tsc": "^1.8.4"
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ dependencies:
|
|||
specifier: ^1.6.0
|
||||
version: 1.6.0
|
||||
daisyui:
|
||||
specifier: ^3.1.9
|
||||
version: 3.1.9(postcss@8.4.25)
|
||||
specifier: ^3.2.1
|
||||
version: 3.2.1
|
||||
pocketbase:
|
||||
specifier: ^0.15.2
|
||||
version: 0.15.2
|
||||
|
@ -45,7 +45,7 @@ devDependencies:
|
|||
version: 5.61.0(eslint@8.44.0)(typescript@5.1.6)
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: ^4.2.3
|
||||
version: 4.2.3(vite@4.4.1)(vue@3.3.4)
|
||||
version: 4.2.3(vite@4.4.2)(vue@3.3.4)
|
||||
autoprefixer:
|
||||
specifier: ^10.4.14
|
||||
version: 10.4.14(postcss@8.4.25)
|
||||
|
@ -61,6 +61,9 @@ devDependencies:
|
|||
eslint-plugin-vue-scoped-css:
|
||||
specifier: ^2.5.0
|
||||
version: 2.5.0(eslint@8.44.0)(vue-eslint-parser@9.3.1)
|
||||
git-commit-info:
|
||||
specifier: ^2.0.2
|
||||
version: 2.0.2
|
||||
pocketbase-typegen:
|
||||
specifier: ^1.1.11
|
||||
version: 1.1.11
|
||||
|
@ -80,8 +83,8 @@ devDependencies:
|
|||
specifier: ^5.1.6
|
||||
version: 5.1.6
|
||||
vite:
|
||||
specifier: ^4.4.1
|
||||
version: 4.4.1(sass@1.63.6)
|
||||
specifier: ^4.4.2
|
||||
version: 4.4.2(sass@1.63.6)
|
||||
vue-eslint-parser:
|
||||
specifier: ^9.3.1
|
||||
version: 9.3.1(eslint@8.44.0)
|
||||
|
@ -645,14 +648,14 @@ packages:
|
|||
eslint-visitor-keys: 3.4.1
|
||||
dev: true
|
||||
|
||||
/@vitejs/plugin-vue@4.2.3(vite@4.4.1)(vue@3.3.4):
|
||||
/@vitejs/plugin-vue@4.2.3(vite@4.4.2)(vue@3.3.4):
|
||||
resolution: {integrity: sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
vite: ^4.0.0
|
||||
vue: ^3.2.25
|
||||
dependencies:
|
||||
vite: 4.4.1(sass@1.63.6)
|
||||
vite: 4.4.2(sass@1.63.6)
|
||||
vue: 3.3.4
|
||||
dev: true
|
||||
|
||||
|
@ -1129,6 +1132,14 @@ packages:
|
|||
- encoding
|
||||
dev: true
|
||||
|
||||
/cross-spawn@5.1.0:
|
||||
resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
|
||||
dependencies:
|
||||
lru-cache: 4.1.5
|
||||
shebang-command: 1.2.0
|
||||
which: 1.3.1
|
||||
dev: true
|
||||
|
||||
/cross-spawn@7.0.3:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
|
@ -1199,11 +1210,9 @@ packages:
|
|||
/csstype@3.1.2:
|
||||
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
|
||||
|
||||
/daisyui@3.1.9(postcss@8.4.25):
|
||||
resolution: {integrity: sha512-GkQR3iLnTfxNsQz7EZXS5bPY65iJM7jdiHtQZWDpRVmBrMlq8Nmrc+t8XmjGdOmJljAPFjtMSD9E9zAnhXF7qg==}
|
||||
/daisyui@3.2.1:
|
||||
resolution: {integrity: sha512-gIqE6wiqoJt9G8+n3R/SwLeUnpNCE2eDhT73rP0yZYVaM7o6zVcakBH3aEW5RGpx3UkonPiLuvcgxRcb2lE8TA==}
|
||||
engines: {node: '>=16.9.0'}
|
||||
peerDependencies:
|
||||
postcss: ^8
|
||||
dependencies:
|
||||
colord: 2.9.3
|
||||
css-selector-tokenizer: 0.8.0
|
||||
|
@ -1327,6 +1336,12 @@ packages:
|
|||
dev: true
|
||||
optional: true
|
||||
|
||||
/end-of-stream@1.4.4:
|
||||
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
||||
dependencies:
|
||||
once: 1.4.0
|
||||
dev: true
|
||||
|
||||
/entities@4.5.0:
|
||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
@ -1566,6 +1581,34 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/execa@0.6.3:
|
||||
resolution: {integrity: sha512-/teX3MDLFBdYUhRk8WCBYboIMUmqeizu0m9Z3YF3JWrbEh/SlZg00vLJSaAGWw3wrZ9tE0buNw79eaAPYhUuvg==}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
cross-spawn: 5.1.0
|
||||
get-stream: 3.0.0
|
||||
is-stream: 1.1.0
|
||||
npm-run-path: 2.0.2
|
||||
p-finally: 1.0.0
|
||||
signal-exit: 3.0.7
|
||||
strip-eof: 1.0.0
|
||||
dev: true
|
||||
|
||||
/execa@4.1.0:
|
||||
resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
cross-spawn: 7.0.3
|
||||
get-stream: 5.2.0
|
||||
human-signals: 1.1.1
|
||||
is-stream: 2.0.1
|
||||
merge-stream: 2.0.0
|
||||
npm-run-path: 4.0.1
|
||||
onetime: 5.1.2
|
||||
signal-exit: 3.0.7
|
||||
strip-final-newline: 2.0.0
|
||||
dev: true
|
||||
|
||||
/fast-deep-equal@3.1.3:
|
||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||
dev: true
|
||||
|
@ -1697,6 +1740,26 @@ packages:
|
|||
dev: true
|
||||
optional: true
|
||||
|
||||
/get-stream@3.0.0:
|
||||
resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/get-stream@5.2.0:
|
||||
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
pump: 3.0.0
|
||||
dev: true
|
||||
|
||||
/git-commit-info@2.0.2:
|
||||
resolution: {integrity: sha512-QOgPqeTkFiIQr3TW/ekG2U6s1x7OkNdR+2XsapmXHiGImO5Qx2cilx2HmGPrihIqmV0WWCo5H+B938lQ/vAAfA==}
|
||||
dependencies:
|
||||
execa: 4.1.0
|
||||
is-git-repository: 1.1.1
|
||||
path-is-absolute: 1.0.1
|
||||
dev: true
|
||||
|
||||
/glob-parent@5.1.2:
|
||||
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
||||
engines: {node: '>= 6'}
|
||||
|
@ -1805,6 +1868,11 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/human-signals@1.1.1:
|
||||
resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==}
|
||||
engines: {node: '>=8.12.0'}
|
||||
dev: true
|
||||
|
||||
/humanize-ms@1.2.1:
|
||||
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
|
||||
dependencies:
|
||||
|
@ -1887,6 +1955,13 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/is-git-repository@1.1.1:
|
||||
resolution: {integrity: sha512-hxLpJytJnIZ5Og5QsxSkzmb8Qx8rGau9bio1JN/QtXcGEFuSsQYau0IiqlsCwftsfVYjF1mOq6uLdmwNSspgpA==}
|
||||
dependencies:
|
||||
execa: 0.6.3
|
||||
path-is-absolute: 1.0.1
|
||||
dev: true
|
||||
|
||||
/is-glob@4.0.3:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -1907,6 +1982,16 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/is-stream@1.1.0:
|
||||
resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/is-stream@2.0.1:
|
||||
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/isexe@2.0.0:
|
||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||
dev: true
|
||||
|
@ -1972,6 +2057,13 @@ packages:
|
|||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
dev: true
|
||||
|
||||
/lru-cache@4.1.5:
|
||||
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
|
||||
dependencies:
|
||||
pseudomap: 1.0.2
|
||||
yallist: 2.1.2
|
||||
dev: true
|
||||
|
||||
/lru-cache@6.0.0:
|
||||
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -2026,6 +2118,10 @@ packages:
|
|||
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
||||
dev: true
|
||||
|
||||
/merge-stream@2.0.0:
|
||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||
dev: true
|
||||
|
||||
/merge2@1.4.1:
|
||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
@ -2049,6 +2145,11 @@ packages:
|
|||
mime-db: 1.52.0
|
||||
dev: true
|
||||
|
||||
/mimic-fn@2.1.0:
|
||||
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/minimatch@3.1.2:
|
||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||
dependencies:
|
||||
|
@ -2224,6 +2325,20 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/npm-run-path@2.0.2:
|
||||
resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==}
|
||||
engines: {node: '>=4'}
|
||||
dependencies:
|
||||
path-key: 2.0.1
|
||||
dev: true
|
||||
|
||||
/npm-run-path@4.0.1:
|
||||
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
dev: true
|
||||
|
||||
/npmlog@5.0.1:
|
||||
resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
|
||||
dependencies:
|
||||
|
@ -2263,6 +2378,13 @@ packages:
|
|||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
|
||||
/onetime@5.1.2:
|
||||
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
mimic-fn: 2.1.0
|
||||
dev: true
|
||||
|
||||
/optionator@0.9.3:
|
||||
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
@ -2275,6 +2397,11 @@ packages:
|
|||
type-check: 0.4.0
|
||||
dev: true
|
||||
|
||||
/p-finally@1.0.0:
|
||||
resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/p-limit@3.1.0:
|
||||
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -2313,6 +2440,11 @@ packages:
|
|||
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
/path-key@2.0.1:
|
||||
resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/path-key@3.1.1:
|
||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -2487,6 +2619,17 @@ packages:
|
|||
dev: true
|
||||
optional: true
|
||||
|
||||
/pseudomap@1.0.2:
|
||||
resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
|
||||
dev: true
|
||||
|
||||
/pump@3.0.0:
|
||||
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
|
||||
dependencies:
|
||||
end-of-stream: 1.4.4
|
||||
once: 1.4.0
|
||||
dev: true
|
||||
|
||||
/punycode@2.1.1:
|
||||
resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -2597,6 +2740,13 @@ packages:
|
|||
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
||||
dev: true
|
||||
|
||||
/shebang-command@1.2.0:
|
||||
resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
shebang-regex: 1.0.0
|
||||
dev: true
|
||||
|
||||
/shebang-command@2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -2604,6 +2754,11 @@ packages:
|
|||
shebang-regex: 3.0.0
|
||||
dev: true
|
||||
|
||||
/shebang-regex@1.0.0:
|
||||
resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/shebang-regex@3.0.0:
|
||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -2719,6 +2874,16 @@ packages:
|
|||
ansi-regex: 5.0.1
|
||||
dev: true
|
||||
|
||||
/strip-eof@1.0.0:
|
||||
resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/strip-final-newline@2.0.0:
|
||||
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/strip-json-comments@3.1.1:
|
||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -2916,8 +3081,8 @@ packages:
|
|||
/util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
/vite@4.4.1(sass@1.63.6):
|
||||
resolution: {integrity: sha512-8mmwPlsy7t+ZcTme7vdbVGuZ3Tri+lrLXr6hsF5UHdyYyARPPPMtM16QlqC9TZuCd5j3NmWs1rwka3cVSRHZTw==}
|
||||
/vite@4.4.2(sass@1.63.6):
|
||||
resolution: {integrity: sha512-zUcsJN+UvdSyHhYa277UHhiJ3iq4hUBwHavOpsNUGsTgjBeoBlK8eDt+iT09pBq0h9/knhG/SPrZiM7cGmg7NA==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
|
@ -3033,6 +3198,13 @@ packages:
|
|||
webidl-conversions: 3.0.1
|
||||
dev: true
|
||||
|
||||
/which@1.3.1:
|
||||
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
dev: true
|
||||
|
||||
/which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
|
@ -3055,6 +3227,10 @@ packages:
|
|||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/yallist@2.1.2:
|
||||
resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
|
||||
dev: true
|
||||
|
||||
/yallist@4.0.0:
|
||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||
dev: true
|
||||
|
|
7
webapp/scripts/generate-version.js
Normal file
7
webapp/scripts/generate-version.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
const fs = require('fs');
|
||||
const gitCommitInfo = require('git-commit-info');
|
||||
const packageJson = require('../package.json');
|
||||
|
||||
const version = `${packageJson.version}+${gitCommitInfo().shortHash}`;
|
||||
|
||||
fs.writeFileSync('.env', `VITE_APP_VERSION=${version}`);
|
|
@ -1,13 +1,16 @@
|
|||
<template>
|
||||
<footer class="footer footer-center bg-base-100 p-4 text-base-content">
|
||||
<div>
|
||||
<p>Version: {{ version }}</p>
|
||||
<p>Made with ❤️ by Simon Giesel</p>
|
||||
<p>Copyright © 2023 - All right reserved</p>
|
||||
<p>Copyright © 2023 - All rights reserved</p>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const version = (import.meta as any).env.VITE_APP_VERSION as string;
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
type="password"
|
||||
required
|
||||
/>
|
||||
<button class="btn gap-2 self-end">
|
||||
<button class="btn-primary btn gap-2 self-end">
|
||||
<ArrowRightOnRectangleIcon class="h-6 w-6" />
|
||||
Login
|
||||
</button>
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
<template>
|
||||
<div
|
||||
v-if="settings"
|
||||
class="h-full overflow-x-auto rounded-lg"
|
||||
class="rounded-lg"
|
||||
>
|
||||
<table class="table-pin-rows table-zebra table">
|
||||
<thead class="uppercase">
|
||||
<thead
|
||||
v-if="!hideHeader"
|
||||
class="uppercase"
|
||||
>
|
||||
<tr>
|
||||
<th v-for="header in tableHeaders">{{ header.title }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-base-100">
|
||||
<tr v-for="entry in data">
|
||||
<tr
|
||||
v-for="entry in data"
|
||||
@click="$emit('click', entry.id)"
|
||||
>
|
||||
<td
|
||||
v-for="header in tableHeaders"
|
||||
:class="{
|
||||
|
@ -29,6 +35,22 @@
|
|||
<span v-else-if="header.type === TableHeaderType.CURRENCY">
|
||||
{{ CurrencyService.toString(entry[header.key]) }}
|
||||
</span>
|
||||
<span v-else-if="header.type === TableHeaderType.SHIFT">
|
||||
<div class="dropdown-bottom dropdown">
|
||||
<label
|
||||
tabindex="0"
|
||||
class="btn bg-base-300 normal-case"
|
||||
>{{ entry[header.key] }} <ChevronDownIcon class="h-4 w-4" /></label>
|
||||
<ul
|
||||
tabindex="0"
|
||||
class="dropdown-content menu rounded-box z-[1] w-52 bg-base-100 p-2 shadow"
|
||||
>
|
||||
<li @click="$emit('selectShift', {id: entry.id, shift: Shifts.NONE}); removeFocus();"><a>{{ Shifts.NONE }}</a></li>
|
||||
<li><a @click="$emit('selectShift', {id: entry.id, shift: Shifts.EARLY}); removeFocus();">{{ Shifts.EARLY }}</a></li>
|
||||
<li><a @click="$emit('selectShift', {id: entry.id, shift: Shifts.LATE}); removeFocus();">{{ Shifts.LATE }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
<RouterLink
|
||||
v-if="header.type === TableHeaderType.BUTTON_ACCOUNT"
|
||||
:to="`/bank?accountNumber=${entry.accountNumber}`"
|
||||
|
@ -41,10 +63,20 @@
|
|||
:for="contactModalId"
|
||||
class="flex items-center gap-2"
|
||||
>
|
||||
<!-- @click="$emit('open-contact-modal', entry.id)" -->
|
||||
<span>{{ CurrencyService.toString(entry[header.key] * settings.minWage) }} / h</span>
|
||||
<div class="btn-ghost btn-sm btn p-1">
|
||||
<PencilSquareIcon class="h-5 w-5" />
|
||||
<div class="dropdown-bottom dropdown">
|
||||
<label
|
||||
tabindex="0"
|
||||
class="btn bg-base-300 normal-case"
|
||||
>{{ CurrencyService.toString(entry[header.key] * settings.minWage) }} / h <ChevronDownIcon class="h-4 w-4" /></label>
|
||||
<ul
|
||||
tabindex="0"
|
||||
class="dropdown-content menu rounded-box z-[1] w-52 bg-base-100 p-2 shadow"
|
||||
>
|
||||
<li
|
||||
v-for="i of settings.maxWageFactor"
|
||||
@click="$emit('selectWage', {id: entry.id, wageFactor: i}); removeFocus();"
|
||||
><a>{{ CurrencyService.toString(settings.minWage * i ) }} / h</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</span>
|
||||
</td>
|
||||
|
@ -56,11 +88,12 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { PropType, onMounted, ref } from 'vue';
|
||||
import { SettingsResponse } from '../../types/pocketbase.types';
|
||||
import { DateService } from '../../services/date.service';
|
||||
import { CurrencyService } from '../../services/currency.service';
|
||||
import { CurrencyDollarIcon, PencilSquareIcon } from '@heroicons/vue/24/outline';
|
||||
import { SettingsService } from '../../services/settings.service';
|
||||
import { SettingsResponse } from '../../types/pocketbase.types';
|
||||
import { Shifts } from '../../enums/shift.enum';
|
||||
import { ChevronDownIcon, CurrencyDollarIcon } from '@heroicons/vue/24/outline';
|
||||
|
||||
const settings = ref<SettingsResponse>();
|
||||
|
||||
|
@ -80,11 +113,26 @@ defineProps({
|
|||
required: false,
|
||||
default: '',
|
||||
},
|
||||
hideHeader: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
settings.value = await SettingsService.getSettings();
|
||||
});
|
||||
|
||||
defineEmits<{
|
||||
click: [id: string],
|
||||
selectShift: [{id: string, shift: Shifts}],
|
||||
selectWage: [{id: string, wageFactor: number}],
|
||||
}>();
|
||||
|
||||
function removeFocus() {
|
||||
(document.activeElement as HTMLElement).blur();
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -95,6 +143,7 @@ export enum TableHeaderType {
|
|||
DATETIME,
|
||||
BUTTON_ACCOUNT,
|
||||
WAGE,
|
||||
SHIFT,
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
86
webapp/src/components/molecules/MoleculeLoginModal.vue
Normal file
86
webapp/src/components/molecules/MoleculeLoginModal.vue
Normal file
|
@ -0,0 +1,86 @@
|
|||
<template>
|
||||
<AtomModal
|
||||
:id="id"
|
||||
ref="modal"
|
||||
:title="title"
|
||||
>
|
||||
<div class="flex flex-col gap-4">
|
||||
<p>{{ description }}</p>
|
||||
<AtomInput
|
||||
v-model="modelValue"
|
||||
placeholder="Passwort"
|
||||
type="password"
|
||||
@keydown.prevent.enter="$emit('login')"
|
||||
/>
|
||||
<p
|
||||
v-if="error"
|
||||
class="alert alert-error"
|
||||
>
|
||||
{{ error }}
|
||||
</p>
|
||||
</div>
|
||||
<template #action>
|
||||
<button
|
||||
class="btn gap-2"
|
||||
:for="id"
|
||||
@click="modal?.close()"
|
||||
>
|
||||
<XCircleIcon class="h-6 w-6" />
|
||||
Schließen
|
||||
</button>
|
||||
<button
|
||||
class="btn gap-2"
|
||||
:for="id"
|
||||
@click.prevent="$emit('login')"
|
||||
>
|
||||
<ArrowRightOnRectangleIcon class="h-6 w-6" />
|
||||
Login
|
||||
</button>
|
||||
</template>
|
||||
</AtomModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { ArrowRightOnRectangleIcon, XCircleIcon } from '@heroicons/vue/24/outline';
|
||||
import AtomModal from '../atoms/AtomModal.vue';
|
||||
import AtomInput from '../atoms/AtomInput.vue';
|
||||
|
||||
const modal = ref<InstanceType<typeof AtomModal>>();
|
||||
|
||||
defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
error: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
show: () => modal.value?.show(),
|
||||
close: () => modal.value?.close(),
|
||||
isOpen: () => modal.value?.isOpen(),
|
||||
});
|
||||
|
||||
/* global defineModel */
|
||||
const modelValue = defineModel();
|
||||
|
||||
defineEmits<{
|
||||
login: [],
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
|
@ -38,7 +38,7 @@
|
|||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
<div class="drawer-side !fixed">
|
||||
<div class="drawer-side !fixed z-50">
|
||||
<label
|
||||
:for="drawerId"
|
||||
class="drawer-overlay"
|
||||
|
@ -47,7 +47,7 @@
|
|||
<li class="pointer-events-none">
|
||||
<AtomLogo class="w-full" />
|
||||
</li>
|
||||
<template v-if="isAuthenticated">
|
||||
<template v-if="isAdmin">
|
||||
<li class="pointer-events-none rounded-md bg-warning uppercase text-warning-content">
|
||||
<span>
|
||||
<ExclamationTriangleIcon class="h-6 w-6" />
|
||||
|
@ -102,7 +102,7 @@ import { ArrowRightOnRectangleIcon, Bars3Icon, ExclamationTriangleIcon, MoonIcon
|
|||
import AtomLogo from '../atoms/AtomLogo.vue';
|
||||
import AtomSwap from '../atoms/AtomSwap.vue';
|
||||
|
||||
const isAuthenticated = ref(false);
|
||||
const isAdmin = ref(false);
|
||||
const hideNavigation = ref(false);
|
||||
const router = useRouter();
|
||||
const drawerCheckbox = ref();
|
||||
|
@ -126,11 +126,11 @@ function getNavigationEntryClass(navigationEntry: INavigationEntry) {
|
|||
};
|
||||
}
|
||||
|
||||
useEventBus<boolean>('isAuthenticated').on(state => (isAuthenticated.value = state));
|
||||
useEventBus<boolean>('isAdmin').on(state => (isAdmin.value = state));
|
||||
useEventBus<boolean>('hideNavigation').on(state => (hideNavigation.value = state));
|
||||
|
||||
onMounted(() => {
|
||||
isAuthenticated.value = AuthService.isAuthenticated();
|
||||
isAdmin.value = AuthService.isAdmin();
|
||||
});
|
||||
|
||||
router.afterEach(() => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<MoleculeAuthDialog v-if="!isAuthenticated" />
|
||||
<MoleculeAuthDialog v-if="!isAdmin" />
|
||||
<div v-else>
|
||||
<slot />
|
||||
</div>
|
||||
|
@ -11,11 +11,11 @@ import { useEventBus } from '@vueuse/core';
|
|||
import { AuthService } from '../../services/auth.service';
|
||||
import MoleculeAuthDialog from '../molecules/MoleculeAuthDialog.vue';
|
||||
|
||||
const isAuthenticated = ref(false);
|
||||
const isAdmin = ref(false);
|
||||
|
||||
useEventBus<boolean>('isAuthenticated').on((state: boolean) => {
|
||||
isAuthenticated.value = state;
|
||||
if(isAuthenticated.value) {
|
||||
useEventBus<boolean>('isAdmin').on((state: boolean) => {
|
||||
isAdmin.value = state;
|
||||
if(isAdmin.value) {
|
||||
emit('authChange', true);
|
||||
} else {
|
||||
emit('authChange', false);
|
||||
|
@ -23,8 +23,8 @@ useEventBus<boolean>('isAuthenticated').on((state: boolean) => {
|
|||
});
|
||||
|
||||
onMounted(() => {
|
||||
isAuthenticated.value = AuthService.isAuthenticated();
|
||||
if(isAuthenticated.value) {
|
||||
isAdmin.value = AuthService.isAdmin();
|
||||
if(isAdmin.value) {
|
||||
emit('authChange', true);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<MoleculeAuthDialog v-if="!isAuthenticated" />
|
||||
<MoleculeAuthDialog v-if="!isAdmin" />
|
||||
<div
|
||||
v-else
|
||||
class="flex h-full flex-col p-6"
|
||||
|
@ -31,7 +31,7 @@ import AtomInput from '../atoms/AtomInput.vue';
|
|||
import MoleculeDataTable, { TableHeaderType } from '../molecules/MoleculeDataTable.vue';
|
||||
import MoleculeAuthDialog from '../molecules/MoleculeAuthDialog.vue';
|
||||
|
||||
const isAuthenticated = ref(false);
|
||||
const isAdmin = ref(false);
|
||||
const accountsSubscription = ref<UnsubscribeFunc>();
|
||||
const transactionsSubscription = ref<UnsubscribeFunc>();
|
||||
|
||||
|
@ -71,9 +71,9 @@ const tableHeaders = [
|
|||
},
|
||||
];
|
||||
|
||||
useEventBus<boolean>('isAuthenticated').on(state => {
|
||||
isAuthenticated.value = state;
|
||||
if(isAuthenticated.value) {
|
||||
useEventBus<boolean>('isAdmin').on(state => {
|
||||
isAdmin.value = state;
|
||||
if(isAdmin.value) {
|
||||
getData();
|
||||
}
|
||||
});
|
||||
|
@ -100,8 +100,8 @@ function search(value: string) {
|
|||
}
|
||||
|
||||
onMounted(async () => {
|
||||
isAuthenticated.value = AuthService.isAuthenticated();
|
||||
if(isAuthenticated.value) {
|
||||
isAdmin.value = AuthService.isAdmin();
|
||||
if(isAdmin.value) {
|
||||
getData();
|
||||
}
|
||||
accountsSubscription.value = await AccountService.subscribeToAccountChanges(async () => {
|
||||
|
|
|
@ -1,34 +1,98 @@
|
|||
<template>
|
||||
<MoleculeAuthDialog v-if="!isAuthenticated" />
|
||||
<div
|
||||
v-else
|
||||
class="flex h-full flex-col p-6"
|
||||
v-if="!isAuthenticated"
|
||||
class="flex min-h-full flex-col p-6"
|
||||
>
|
||||
<h1 class="mb-4 text-4xl">Musterfirma</h1>
|
||||
<h2 class="mb-4 text-3xl">Kontostand: 500 Batzen</h2>
|
||||
<AtomInput
|
||||
v-model="searchQuery"
|
||||
placeholder="Firmenname eingeben"
|
||||
class="mb-4"
|
||||
/>
|
||||
<MoleculeDataTable
|
||||
v-if="companies"
|
||||
class="cursor-pointer"
|
||||
:table-headers="companyTableHeaders"
|
||||
:data="companies"
|
||||
hide-header
|
||||
@click="showLoginDialog"
|
||||
/>
|
||||
<MoleculeLoginModal
|
||||
id="login-modal"
|
||||
ref="loginModal"
|
||||
v-model="password"
|
||||
:title="selectedCompany?.name ?? ''"
|
||||
description="Bitte gib dein Passwort ein, um das Firmenportal anzuzeigen."
|
||||
:error="error"
|
||||
@login="login"
|
||||
@close="password = ''; error = ''"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="company"
|
||||
class="flex min-h-full flex-col p-6"
|
||||
>
|
||||
<div class="mb-4 flex flex-col gap-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-4xl">{{ company.name }}</h1>
|
||||
<button
|
||||
class="btn-primary btn w-48"
|
||||
@click="logout()"
|
||||
>
|
||||
<ArrowLeftOnRectangleIcon class="h-6 w-6" />
|
||||
Abmelden
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-2xl">500,00 Batzen</h2>
|
||||
<button class="btn-primary btn-disabled btn w-48">
|
||||
<BanknotesIcon class="h-6 w-6" />
|
||||
Transaktionen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<MoleculeDataTable
|
||||
v-if="accounts"
|
||||
:table-headers="tableHeaders"
|
||||
:table-headers="accountTableHeaders"
|
||||
:data="accounts"
|
||||
@select-shift="selectShift"
|
||||
@select-wage="selectWage"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { useEventBus } from '@vueuse/core';
|
||||
import { AccountsListResponse } from '../../types/pocketbase.types';
|
||||
import { onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
import { RecordSubscription, UnsubscribeFunc } from 'pocketbase';
|
||||
import { AccountsResponse, CompaniesResponse } from '../../types/pocketbase.types';
|
||||
import { AccountService } from '../../services/account.service';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { CompanyService } from '../../services/company.service';
|
||||
import { Shifts } from '../../enums/shift.enum';
|
||||
import { ArrowLeftOnRectangleIcon, BanknotesIcon } from '@heroicons/vue/24/outline';
|
||||
import AtomInput from '../atoms/AtomInput.vue';
|
||||
import MoleculeDataTable, { TableHeaderType } from '../molecules/MoleculeDataTable.vue';
|
||||
import MoleculeAuthDialog from '../molecules/MoleculeAuthDialog.vue';
|
||||
import MoleculeLoginModal from '../molecules/MoleculeLoginModal.vue';
|
||||
|
||||
const isAuthenticated = ref(false);
|
||||
|
||||
const accounts = ref<AccountsListResponse<number, string>[]>([]);
|
||||
const initAccounts = ref<AccountsListResponse<number, string>[]>([]);
|
||||
const loginModal = ref<InstanceType<typeof MoleculeLoginModal>>();
|
||||
const searchQuery = ref('');
|
||||
const tableHeaders = [
|
||||
const password = ref('');
|
||||
const companies = ref<CompaniesResponse[]>([]);
|
||||
const initCompanies = ref<CompaniesResponse[]>([]);
|
||||
const selectedCompany = ref<CompaniesResponse>();
|
||||
const company = ref<CompaniesResponse>();
|
||||
const accounts = ref<AccountsResponse[]>([]);
|
||||
const isAuthenticated = ref(false);
|
||||
const accountsSubscription = ref<UnsubscribeFunc>();
|
||||
const error = ref('');
|
||||
|
||||
const companyTableHeaders = [
|
||||
{
|
||||
title: '',
|
||||
key: 'name',
|
||||
type: TableHeaderType.STRING,
|
||||
},
|
||||
];
|
||||
|
||||
const accountTableHeaders = [
|
||||
{
|
||||
title: 'Vorname',
|
||||
key: 'firstName',
|
||||
|
@ -40,9 +104,9 @@ const tableHeaders = [
|
|||
type: TableHeaderType.STRING,
|
||||
},
|
||||
{
|
||||
title: 'Schicht (bearbeitbar)',
|
||||
title: 'Schicht',
|
||||
key: 'shift',
|
||||
type: TableHeaderType.STRING,
|
||||
type: TableHeaderType.SHIFT,
|
||||
},
|
||||
{
|
||||
title: 'Lohn',
|
||||
|
@ -51,16 +115,9 @@ const tableHeaders = [
|
|||
},
|
||||
];
|
||||
|
||||
useEventBus<boolean>('isAuthenticated').on(state => {
|
||||
isAuthenticated.value = state;
|
||||
if(isAuthenticated.value) {
|
||||
getData();
|
||||
}
|
||||
});
|
||||
|
||||
async function getData() {
|
||||
initAccounts.value = await AccountService.getAccountsByCompanyId('c09ncb3l2pi6i0u');
|
||||
accounts.value = initAccounts.value;
|
||||
initCompanies.value = await CompanyService.getCompanies();
|
||||
companies.value = initCompanies.value;
|
||||
}
|
||||
|
||||
watch(
|
||||
|
@ -70,20 +127,77 @@ watch(
|
|||
},
|
||||
);
|
||||
|
||||
function search(value: string) {
|
||||
if(initAccounts.value) {
|
||||
accounts.value = initAccounts.value.filter((account) =>
|
||||
account.name?.toLocaleLowerCase().includes(value.toLocaleLowerCase()),
|
||||
function search(value: string): void {
|
||||
if(initCompanies.value) {
|
||||
companies.value = initCompanies.value.filter((company) =>
|
||||
company.name?.toLocaleLowerCase().includes(value.toLocaleLowerCase()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
isAuthenticated.value = AuthService.isAuthenticated();
|
||||
isAuthenticated.value = CompanyService.isAuthenticated();
|
||||
if(isAuthenticated.value) {
|
||||
init();
|
||||
} else {
|
||||
getData();
|
||||
}
|
||||
});
|
||||
|
||||
async function init() {
|
||||
company.value = await CompanyService.getCompany();
|
||||
accounts.value = await AccountService.getAccountsByCompanyId(company.value.id);
|
||||
accountsSubscription.value = await AccountService.subscribeToAccountChanges(async (data: RecordSubscription<AccountsResponse>) => {
|
||||
if(data.action === 'update') {
|
||||
accounts.value = accounts.value.map((account) => {
|
||||
if(account.id === data.record.id) {
|
||||
return data.record;
|
||||
}
|
||||
return account;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showLoginDialog(id: string): void {
|
||||
selectedCompany.value = companies.value.find((company) => company.id === id);
|
||||
loginModal.value?.show();
|
||||
}
|
||||
|
||||
async function login(): Promise<void> {
|
||||
if(selectedCompany.value) {
|
||||
try {
|
||||
await CompanyService.login(selectedCompany.value?.username, password.value);
|
||||
} catch {
|
||||
error.value = 'Fehler beim Login. Bitte Passwort überprüfen.';
|
||||
return;
|
||||
}
|
||||
isAuthenticated.value = true;
|
||||
await init();
|
||||
loginModal.value?.close();
|
||||
}
|
||||
}
|
||||
|
||||
async function selectShift(shiftChange: {id: string, shift: Shifts}): Promise<void> {
|
||||
await AccountService.updateShift(shiftChange.id, shiftChange.shift);
|
||||
}
|
||||
|
||||
async function selectWage(wageChange: {id: string, wageFactor: number}): Promise<void> {
|
||||
await AccountService.updateWage(wageChange.id, wageChange.wageFactor);
|
||||
}
|
||||
|
||||
function logout() {
|
||||
CompanyService.logout();
|
||||
isAuthenticated.value = false;
|
||||
selectedCompany.value = undefined;
|
||||
company.value = undefined;
|
||||
accounts.value = [];
|
||||
getData();
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
accountsSubscription.value?.();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -162,6 +162,7 @@ import { SettingsResponse } from '../../types/pocketbase.types';
|
|||
import { AccountService } from '../../services/account.service';
|
||||
import { CompanyService } from '../../services/company.service';
|
||||
import { SettingsService } from '../../services/settings.service';
|
||||
import { Shifts } from '../../enums/shift.enum';
|
||||
import {
|
||||
BriefcaseIcon,
|
||||
ExclamationTriangleIcon,
|
||||
|
@ -214,7 +215,7 @@ async function importAccounts(file: File): Promise<void> {
|
|||
lastName: lastName.trim(),
|
||||
grade: grade.trim(),
|
||||
company: company?.id,
|
||||
shift: 'Keine Schicht',
|
||||
shift: Shifts.NONE,
|
||||
wageFactor: 1,
|
||||
}));
|
||||
}
|
||||
|
|
5
webapp/src/enums/shift.enum.ts
Normal file
5
webapp/src/enums/shift.enum.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export enum Shifts {
|
||||
NONE = 'Keine Schicht',
|
||||
EARLY = 'Frühschicht',
|
||||
LATE = 'Spätschicht'
|
||||
}
|
|
@ -16,12 +16,18 @@ export class AccountService {
|
|||
public static async getAccounts(): Promise<AccountsListResponse<number, string>[]> {
|
||||
return VIEW.getFullList();
|
||||
}
|
||||
public static getAccountsByCompanyId(companyId: string): Promise<AccountsListResponse<number, string>[]> {
|
||||
public static getAccountsByCompanyId(companyId: string): Promise<AccountsResponse[]> {
|
||||
return COLLECTION.getFullList({ filter: `company.id = "${companyId}"` });
|
||||
}
|
||||
public static async addAccount(account: AccountsRecord): Promise<AccountsResponse> {
|
||||
return COLLECTION.create(account, { $cancelKey: `${account.firstName}.${account.lastName}.${account.grade}` });
|
||||
}
|
||||
public static async updateShift(accountId: string, shift: string): Promise<AccountsResponse> {
|
||||
return COLLECTION.update(accountId, { shift });
|
||||
}
|
||||
public static async updateWage(accountId: string, wageFactor: number): Promise<AccountsResponse> {
|
||||
return COLLECTION.update(accountId, { wageFactor });
|
||||
}
|
||||
|
||||
public static async subscribeToAccountChanges(
|
||||
callback: (data: RecordSubscription<AccountsResponse>)=> void,
|
||||
|
|
|
@ -5,15 +5,15 @@ import { useEventBus } from '@vueuse/core';
|
|||
const API = PocketbaseService.getApi();
|
||||
|
||||
export class AuthService {
|
||||
public static isAuthenticated(): boolean {
|
||||
if(API.authStore.isValid) {
|
||||
return true;
|
||||
public static isAdmin(): boolean {
|
||||
if(API.authStore.isValid && API.authStore.model) {
|
||||
return API.authStore.model.constructor.name === 'Admin';
|
||||
}
|
||||
this.logout();
|
||||
return false;
|
||||
}
|
||||
public static getAdmin(): Admin {
|
||||
if(this.isAuthenticated()) {
|
||||
if(this.isAdmin()) {
|
||||
return API.authStore.model as Admin;
|
||||
}
|
||||
throw new Error('Not authenticated');
|
||||
|
@ -21,13 +21,13 @@ export class AuthService {
|
|||
public static async loginAsAdmin(email: string, password: string): Promise<Admin> {
|
||||
const response = await API.admins.authWithPassword(email, password);
|
||||
if(response) {
|
||||
useEventBus<boolean>('isAuthenticated').emit(true);
|
||||
useEventBus<boolean>('isAdmin').emit(true);
|
||||
return response.admin;
|
||||
}
|
||||
throw new Error('Invalid credentials');
|
||||
}
|
||||
public static logout(): void {
|
||||
API.authStore.clear();
|
||||
useEventBus<boolean>('isAuthenticated').emit(false);
|
||||
useEventBus<boolean>('isAdmin').emit(false);
|
||||
}
|
||||
}
|
|
@ -1,13 +1,43 @@
|
|||
import { RecordAuthResponse } from 'pocketbase';
|
||||
import { Collections, CompaniesRecord, CompaniesResponse } from '../types/pocketbase.types';
|
||||
import { PocketbaseService } from './pocketbase.service';
|
||||
import { useEventBus } from '@vueuse/core';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
const COLLECTION = PocketbaseService.getApi().collection(Collections.Companies);
|
||||
const API = PocketbaseService.getApi();
|
||||
const COLLECTION = API.collection(Collections.Companies);
|
||||
|
||||
export class CompanyService {
|
||||
public static async addCompany(company: CompaniesRecord & {password: string}): Promise<CompaniesResponse> {
|
||||
return COLLECTION.create({ ...company, passwordConfirm: company.password }, { $cancelKey: `${company.name}` });
|
||||
}
|
||||
public static async getCompanies(): Promise<CompaniesResponse[]> {
|
||||
return COLLECTION.getFullList();
|
||||
return COLLECTION.getFullList({ sort: 'name' });
|
||||
}
|
||||
public static async login(username: string, password: string): Promise<RecordAuthResponse<CompaniesResponse>> {
|
||||
try {
|
||||
const response = await COLLECTION.authWithPassword<CompaniesResponse>(username, password);
|
||||
useEventBus<boolean>('isAdmin').emit(AuthService.isAdmin());
|
||||
return response;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
public static isAuthenticated(): boolean {
|
||||
if(API.authStore.isValid && API.authStore.model) {
|
||||
return API.authStore.model.constructor.name === 'Record';
|
||||
}
|
||||
this.logout();
|
||||
return false;
|
||||
}
|
||||
public static logout(): void {
|
||||
API.authStore.clear();
|
||||
}
|
||||
public static async getCompany(): Promise<CompaniesResponse> {
|
||||
if(this.isAuthenticated()) {
|
||||
return API.authStore.model as unknown as CompaniesResponse;
|
||||
}
|
||||
throw new Error('Not authenticated');
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue