Compare commits

..

1312 Commits

Author SHA1 Message Date
philipp 481f6b686e feat: improve toasts
Build Latest and dev images / build-container (push) Successful in 1m0s
2025-03-28 11:44:10 +01:00
philipp e7a69ebdca feat: improve modals 2025-03-28 11:40:35 +01:00
philipp 194c3c4886 feat: improved track deletion ui feedback 2025-03-28 11:37:47 +01:00
philipp f5a46aa203 feat: modal improvements 2025-03-28 11:37:06 +01:00
philipp 443371e2fd feat: improve modals 2025-03-28 11:29:30 +01:00
philipp d7ab9247cd feat: improve translations 2025-03-28 11:26:52 +01:00
philipp a2cd54fba4 feat: improve ConfirmTeamDeletionModal
Build Latest and dev images / build-container (push) Successful in 1m0s
2025-03-28 11:16:44 +01:00
philipp 9048f3df77 feat: improve translations 2025-03-28 11:15:12 +01:00
philipp fecf3b59a3 feat: improved ConfirmOrgDeletionModal
Build Latest and dev images / build-container (push) Successful in 1m2s
2025-03-28 11:11:21 +01:00
philipp 18a4623e71 feat: improved translations 2025-03-28 11:11:08 +01:00
philipp 968a7ccc0e feat: improved sidebar z-index 2025-03-28 11:10:54 +01:00
philipp 6249502a88 🚀RELEASE v1.8.2
Build Latest and dev images / build-container (push) Successful in 1m1s
Build release images / build-container (push) Successful in 56s
2025-03-26 22:02:25 +01:00
philipp 8a78034079 feat(dashboard): active item for teams + runners
Build Latest and dev images / build-container (push) Successful in 57s
2025-03-26 22:01:18 +01:00
philipp 7633b7b056 feat: improvement of card,certificate,sponsoringcontract action buttons
Build Latest and dev images / build-container (push) Successful in 1m1s
2025-03-26 21:59:55 +01:00
niggl b8e6b24bf3 🚀RELEASE v1.8.1
Build release images / build-container (push) Successful in 1m18s
Build Latest and dev images / build-container (push) Successful in 1m21s
2025-03-26 19:12:05 +01:00
niggl 97b7ca931f fix(pdf_generation): Only load direct runners for direct calls 2025-03-26 19:10:37 +01:00
philipp 48dd9acde5 🚀RELEASE v1.8.0
Build release images / build-container (push) Successful in 1m13s
Build Latest and dev images / build-container (push) Successful in 1m15s
2025-03-26 16:03:19 +01:00
philipp 5147a20b3c fix(DonorDetail): donor deletion
Build Latest and dev images / build-container (push) Successful in 1m20s
2025-03-26 15:57:44 +01:00
philipp bb2319a78d chore(deps): bump
Build Latest and dev images / build-container (push) Failing after 23s
2025-03-26 15:35:53 +01:00
philipp 7c10d95c1c feat(RunnerOrganizationService.runnerOrganizationControllerGetRunners): load all runners in org
Build Latest and dev images / build-container (push) Successful in 1m7s
2025-03-26 15:34:38 +01:00
philipp f734d1e3f6 feat: cleanup TeamDetail + OrgDetail 2025-03-26 15:33:34 +01:00
niggl e567bb35c3 fix(ci): Correct tag pattern syntax in release workflow
Build Latest and dev images / build-container (push) Successful in 58s
2025-03-22 22:39:20 +01:00
niggl 3ec18a6964 refactor(ci): Add Gitea workflow for building release images and remove Woodpecker configuration
Build Latest and dev images / build-container (push) Successful in 1m53s
2025-03-22 22:38:43 +01:00
niggl 847fa288f1 refactor(ci): Switch to actions for dev 2025-03-22 22:33:59 +01:00
philipp 824ecfab2e wip 2025-03-20 22:29:36 +01:00
philipp 5f5d8277b9 wip 2025-03-20 22:15:36 +01:00
philipp 0a6cf619b0 wip 2025-03-20 22:13:41 +01:00
philipp 050a146ae0 wip 2025-03-20 21:52:39 +01:00
philipp 1bc53146b9 wip 2025-03-20 21:51:00 +01:00
philipp e82350df4a wip 2025-03-20 21:42:02 +01:00
philipp 3d3ce2918b wip 2025-03-20 21:34:51 +01:00
philipp 79e6a4212d feat: improve input readability 2025-03-20 21:31:33 +01:00
philipp 37cdbba0a3 wip 2025-03-20 21:31:03 +01:00
philipp c37fb98bed feat: improve fonts + button positions 2025-03-20 21:29:10 +01:00
philipp 975f145444 feat(dashboard): full width for sidebar items 2025-03-18 00:46:29 +01:00
philipp 391186d01f feat: athiti font 2025-03-18 00:46:10 +01:00
niggl ae056cd88c 🚀RELEASE v1.7.0
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/tag/release Pipeline was successful
2024-12-17 17:41:11 +01:00
niggl 7f989b206b fix(pdfgeneration): Added parent_group
ci/woodpecker/push/build Pipeline failed
2024-12-17 17:40:19 +01:00
niggl 65ce02e777 refactor(cards): Switched over to new document-server api
ci/woodpecker/push/build Pipeline was successful
2024-12-17 17:32:33 +01:00
niggl 878d9714cb refactor(pdfgeneration): Switch to new document-server api
ci/woodpecker/push/build Pipeline failed
2024-12-17 17:29:42 +01:00
niggl f99b7f4bb8 refactor(pdfgeneration): Switched contract generation over to new document-server
ci/woodpecker/push/build Pipeline was successful
2024-12-17 17:19:20 +01:00
niggl e23098410c refactor(pdfgeneration): Switch cards over to new service 2024-12-17 17:09:55 +01:00
niggl 04494d2a2a chore: bump
ci/woodpecker/tag/release Pipeline was successful
ci/woodpecker/push/build Pipeline was successful
2024-12-11 17:30:49 +01:00
niggl e2d6fbb513 refactor(orgs): Swtich to new selfservice baseurl 2024-12-11 17:29:14 +01:00
niggl 477c650f3f 🚀RELEASE v1.5.3
ci/woodpecker/tag/release Pipeline was successful
ci/woodpecker/push/build Pipeline was successful
2024-11-26 19:20:04 +01:00
niggl fc15c68cba feat(dx): Yarn support
ci/woodpecker/push/build Pipeline failed
2024-11-26 19:19:31 +01:00
niggl 32b5f5420b refactor(ci): Only build licences, don't export
ci/woodpecker/push/build Pipeline was successful
2024-11-26 19:11:14 +01:00
niggl ee87f82799 fix(ci): Update git pushb settings
ci/woodpecker/push/build Pipeline failed
2024-11-26 19:06:32 +01:00
niggl 7c08f522aa fix(ci): Update relase machanism 2024-11-26 19:06:16 +01:00
niggl e211554579 fix(ci): Install pnpm
ci/woodpecker/push/build Pipeline failed
2024-11-26 19:01:51 +01:00
niggl 7ba890dfd7 fix(ci): Switch over to new woodpecker version
ci/woodpecker/push/build Pipeline failed
2024-11-26 18:59:42 +01:00
philipp 68b4309164 chore(deps): bump some 2024-11-21 18:05:11 +01:00
philipp d803f3d490 fix: unexpected/ missing props 2024-11-21 17:05:06 +01:00
philipp 5468766d87 fix(orgs): ImportRunnerModal props 2024-11-21 17:00:03 +01:00
philipp e967d8d20c feat(dashboard): reorder menu items 2024-11-21 16:59:48 +01:00
philipp ad4db882f0 feat: cleanup random page toasts 2024-11-21 16:56:10 +01:00
philipp 84aa846b87 feat(about): cleanup ui 2024-11-21 16:55:58 +01:00
philipp 3532968b33 🚀RELEASE v1.5.2 2024-11-21 10:33:56 +01:00
philipp 6bb49db4ee feat(dashboard): add lfk icon and app name to mobile nav bar 2024-11-21 10:24:23 +01:00
philipp 38fb111f7a feat: improved mobile buttons + search ui 2024-11-21 10:22:06 +01:00
philipp a50447f457 feat(dashboard): improved a11y of active sidebar menu item 2024-11-21 10:14:22 +01:00
philipp b1a2044631 feat(dashboard): match greeting style with rest of titles 2024-11-21 10:11:03 +01:00
philipp c883920caa feat: improved dashboard titles ui + a11y 2024-11-21 10:09:14 +01:00
philipp 21453ef272 feat: improved dashboard titles ui + a11y 2024-11-21 10:07:20 +01:00
philipp 10182433f8 feat(i18n/de): rename "Track" to "Laufstrecke" 2024-11-21 10:04:38 +01:00
philipp b338f33a63 feat(dashboard): improved mobile ui hamburger button 2024-11-21 09:58:15 +01:00
philipp cb82200481 feat(users/UsersOverview): improve ui by adding borders to badges 2024-11-21 09:57:50 +01:00
philipp 9abf74d6d2 🚀RELEASE v1.5.1 2024-11-21 09:46:27 +01:00
philipp 50e81a6cb5 fix(dockerfile): AS casing 2024-11-21 09:45:51 +01:00
philipp 8fae1fb6b3 chore(deps): bump some 2024-11-21 09:45:39 +01:00
philipp 372fa110ec fix(scanstations): CopyScanStationTokenModal open after create 2024-11-21 09:40:32 +01:00
philipp 35bec9fe58 chore(deps): pnpm@9 2024-11-21 09:33:22 +01:00
philipp 93d67bdba9 chore(deps): node:23.2.0 2024-11-21 09:32:58 +01:00
philipp a5e72a18e3 refactor(scanstations/CopyScanStationTokenModal): drop dispatch 2024-11-21 09:31:45 +01:00
philipp 91d2f46b93 fix(config): add explicit window.config 2024-11-21 09:31:09 +01:00
philipp c60bae4533 fix(tracks/AddTrackModal): i18n 2024-11-21 09:30:52 +01:00
philipp 43ac878d44 fix: tailwind config 2024-11-21 09:30:24 +01:00
niggl ceabd06a43 🚀RELEASE v1.5.0 2024-11-20 19:29:18 +01:00
niggl 9bfc0c5338 fix(components): Add missing toast imports 2024-11-20 19:28:07 +01:00
niggl fb8206ff13 feat(ci)!: Switch to woodpecker
ci/woodpecker/push/build Pipeline was successful
2023-11-06 19:51:01 +01:00
niggl dceb0ef461 🚀RELEASE v1.4.13
continuous-integration/drone/push Build encountered an error
2023-07-31 18:55:53 +02:00
niggl 88bc1982ca Show donations as euro in export 2023-07-31 18:55:09 +02:00
niggl e741a9d7e7 Merge branch 'dev' of git.odit.services:lfk/frontend into dev
continuous-integration/drone/push Build is passing
2023-05-18 21:35:28 +02:00
niggl 65f1d22205 🚀RELEASE v1.4.12 2023-05-18 21:35:16 +02:00
niggl d867c08aba fix(donation/payment): Funny javascript number to float conversion where integers were needed 2023-05-18 21:34:41 +02:00
niggl 6193eff38e new license file version [CI SKIP] 2023-05-10 11:29:03 +00:00
niggl f1929e7cf9 Merge branch 'dev' of git.odit.services:lfk/frontend into dev
continuous-integration/drone/push Build is passing
2023-05-10 13:28:43 +02:00
niggl 373484c242 🚀RELEASE v1.4.11 2023-05-10 13:28:34 +02:00
niggl f77460bb0c chore(deps): Lockfile 2023-05-10 13:28:21 +02:00
niggl 574e0dcb05 feat(orgs): Show total distance 2023-05-10 13:27:47 +02:00
niggl 7b19a0aa08 chore(deps): More bumps 2023-05-10 13:22:11 +02:00
niggl 08642d7618 new license file version [CI SKIP] 2023-05-10 11:21:43 +00:00
niggl c3e9c27cd3 🚀RELEASE v1.4.10
continuous-integration/drone/push Build is passing
2023-05-10 13:21:10 +02:00
niggl 29a2854671 chore(deps): Bumped svelte-table 2023-05-10 13:20:44 +02:00
niggl 8e6786e722 chore(deps): Pin and bump 2023-05-10 13:19:25 +02:00
niggl 6ad40564e3 chore(deps): Bumped scanclientjs 2023-05-10 13:18:44 +02:00
niggl 776973bfe9 🚀RELEASE v1.4.9
continuous-integration/drone/push Build is passing
2023-05-09 16:32:00 +02:00
niggl 6025e43baa Fixed empty return 2023-05-09 16:29:41 +02:00
niggl d9a47f882c Changed the in table replacement method 2023-05-09 16:29:25 +02:00
niggl 4235758a6d 🚀RELEASE v1.4.8
continuous-integration/drone/push Build is passing
2023-05-09 10:44:04 +02:00
niggl 59fe2dfabb Switched donor loading to non-paginated 2023-05-09 10:43:33 +02:00
niggl 6364536dcd 🚀RELEASE v1.4.7
continuous-integration/drone/push Build is passing
2023-05-04 20:30:20 +02:00
niggl a8a771114d Paginated modal data loading 2023-05-04 20:28:21 +02:00
niggl 4e0a2c8301 Moved loading to onmount 2023-05-04 20:17:29 +02:00
niggl b6fed92a17 🚀RELEASE v1.4.6
continuous-integration/drone/push Build is passing
2023-05-04 20:10:57 +02:00
niggl 97b57aeb0c fix(donor/detail): Set email to null to avoid vaidation errors 2023-05-04 20:10:21 +02:00
niggl e25ed1fff9 fix(donor/detail): Set phone to null to avoid vaidation errors 2023-05-04 20:09:43 +02:00
niggl a2ff5b8a14 fix(donor/details): don't load donations 2023-05-04 20:07:54 +02:00
niggl 0284f18beb 🚀RELEASE v1.4.5
continuous-integration/drone/push Build is passing
2023-05-04 20:04:02 +02:00
niggl 803d64c78c fix: Removed dynamic pagesize adjustments
continuous-integration/drone/push Build is passing
2023-05-04 20:03:23 +02:00
niggl dacb2f8ace Revert "revert: buggy pagination"
This reverts commit b2648645e8.
2023-05-04 19:57:46 +02:00
philipp b7a53960e5 🚀RELEASE v1.4.4
continuous-integration/drone/push Build is passing
2023-05-04 14:44:31 +02:00
philipp 66f1e6b4fe fix(AddDonationModal): missing toast dismiss on success distance donation
continuous-integration/drone/push Build is failing
2023-05-04 14:44:17 +02:00
philipp 33166bfafc 🚀RELEASE v1.4.3
continuous-integration/drone/push Build is passing
2023-05-04 14:32:56 +02:00
philipp b2648645e8 revert: buggy pagination
continuous-integration/drone/push Build is failing
2023-05-04 14:32:37 +02:00
philipp 53e3ddb751 🚀RELEASE v1.4.2
continuous-integration/drone/push Build is passing
2023-05-04 13:55:14 +02:00
philipp edc2dcab92 fix(DonorDetail): missing toast import
continuous-integration/drone/push Build is passing
2023-05-04 13:53:59 +02:00
philipp d49f545d94 fix(GenerateRunnerCertificates): missing toast import
continuous-integration/drone/push Build is failing
2023-05-04 13:53:42 +02:00
niggl 3b98c99b72 🚀RELEASE v1.4.1
continuous-integration/drone/push Build is passing
2023-05-01 15:10:55 +02:00
niggl 1da775a09b Fixed translation 2023-05-01 15:10:18 +02:00
niggl f0475bd9a0 🚀RELEASE v1.4.0
continuous-integration/drone/push Build is passing
2023-05-01 15:08:03 +02:00
niggl 15d8afefbb Bump dockerfile node
continuous-integration/drone/push Build is passing
2023-05-01 15:06:15 +02:00
niggl f3bcc01685 Pinned config files used
continuous-integration/drone/push Build is passing
2023-05-01 15:04:58 +02:00
niggl 95238606d5 Switched build image node version
continuous-integration/drone/push Build is failing
2023-05-01 15:01:49 +02:00
niggl bbf8170cb9 Updated store directory for dockerfil
continuous-integration/drone/push Build is failing
2023-05-01 14:59:36 +02:00
niggl 8c628f23dc Merge pull request 'next' (#180) from next into dev
continuous-integration/drone/push Build is failing
Reviewed-on: #180
2023-05-01 12:55:19 +00:00
philipp 811f5d5754 monospace fonts for IDs in overviews 2023-05-01 14:53:34 +02:00
philipp 69ec7fc1fe ScansOverview full month formatting 2023-05-01 14:42:56 +02:00
niggl 064197d222 Dynamicly adjust page size for large datasets 2023-05-01 14:35:46 +02:00
niggl e9cf2bc849 Full track table editing 2023-05-01 14:27:56 +02:00
niggl 103ad57ddc Added track update toasts 2023-05-01 14:25:22 +02:00
niggl 2856c5c1b7 Editing update logic 2023-05-01 14:23:25 +02:00
niggl a953349c14 Updated the track editing switch logic 2023-05-01 14:13:40 +02:00
niggl 175d86745f Added edit button for trackscans 2023-05-01 14:05:44 +02:00
niggl 081a141218 Implemented delete for new track table 2023-05-01 14:03:46 +02:00
philipp e904ab0b84 fix: a11y in About page 2023-04-27 08:30:12 +02:00
philipp a2f9dbbe01 text cleanups, StatCard improvements 2023-04-27 08:29:07 +02:00
philipp 8b922309b9 drop gridjs (TracksOverview Actions will need to be re-implemented) 2023-04-26 23:26:07 +02:00
philipp 4c81e3c432 a11y improvements 2023-04-26 23:14:15 +02:00
philipp 6c1a707166 cleanup legacy TeamsOverview text 2023-04-26 23:12:03 +02:00
philipp 7d8253618b improved StatCard readability 2023-04-26 23:11:01 +02:00
philipp dbaf85799a improved login 2023-04-26 23:09:47 +02:00
philipp daeea24e0e drop middlename for admin users 2023-04-26 23:08:25 +02:00
philipp 0fca0352c5 a11y fix OrgOverview 2023-04-26 23:03:53 +02:00
philipp 8eaad8219a add missing striped tables 2023-04-26 23:02:13 +02:00
philipp 6bc92f4a08 a11y cleanup 2023-04-26 23:02:06 +02:00
philipp 8be40e2d80 translations 2023-04-26 22:58:17 +02:00
philipp 01b415d4cb fix: scan laptime formatting 2023-04-26 22:56:38 +02:00
philipp 5e82638f35 striped tabled 2023-04-26 22:51:57 +02:00
philipp 46d076af9d formatting, full migration to svelte-french-toast 2023-04-26 22:47:42 +02:00
philipp 38a665024e new license file version [CI SKIP] 2023-04-22 09:47:15 +00:00
philipp d32eb8266b README update
continuous-integration/drone/push Build is passing
2023-04-22 11:45:47 +02:00
philipp bc4ac0f316 drop legacy ThFilter components 2023-04-22 11:45:40 +02:00
philipp 6952b8727f drop propfilepic 2023-04-22 11:41:51 +02:00
philipp 81d4da6550 chore(deps): node:20.0.0 2023-04-22 11:39:32 +02:00
philipp 6154ca7ddf chore(deps): bump all 2023-04-22 11:39:14 +02:00
philipp 8fb1e0ca0f svelte-french-toast + translations
continuous-integration/drone/push Build is failing
2023-04-22 11:22:38 +02:00
philipp 763a01af09 cleanup MainDashContent 2023-04-22 11:16:57 +02:00
philipp 663cb29ccd translation cleanups 2023-04-22 11:16:50 +02:00
philipp 56c3365656 add svelte-french-toast
continuous-integration/drone/push Build is failing
2023-04-22 11:11:50 +02:00
niggl e7b2c64798 🚀RELEASE v1.3.4
continuous-integration/drone/push Build is failing
2023-04-19 18:23:17 +02:00
niggl 7cb6b63eb9 Smaller sponsoring page size 2023-04-19 18:23:07 +02:00
niggl d6d88f5f60 🚀RELEASE v1.3.3
continuous-integration/drone/push Build is failing
2023-04-19 18:18:44 +02:00
niggl 2c208c4381 bumped lfk-client-js 2023-04-19 18:18:26 +02:00
niggl 39bc6c4945 🚀RELEASE v1.3.2
continuous-integration/drone/push Build is failing
2023-04-19 18:17:18 +02:00
niggl b94e3b745f fix(donors): Shortened texts 2023-04-19 18:16:50 +02:00
niggl 6f337aeee1 feat(donations): Resolve donations via donor 2023-04-19 18:15:15 +02:00
niggl 5d48060834 fix(donors): Removed debug infos 2023-04-19 18:12:24 +02:00
niggl c842c203e2 🚀RELEASE v1.3.1
continuous-integration/drone/push Build is passing
2023-04-19 18:00:58 +02:00
niggl 5bcfc8db75 More filtering 2023-04-19 18:00:41 +02:00
niggl 27b4dde755 feat(donors): Added name and address filtering 2023-04-19 18:00:16 +02:00
niggl 91ab199769 feat(donations): Donation table filtering 2023-04-19 17:53:24 +02:00
niggl e75be49be4 🚀RELEASE v1.3.0
continuous-integration/drone/push Build is passing
2023-04-19 17:41:40 +02:00
niggl 505fb8cb08 feat(donations): Implemented donation deletion via confirm modal 2023-04-19 17:41:21 +02:00
niggl e5c9265588 feat(donations): Implemented add donation payment via datatable refresh 2023-04-19 17:34:34 +02:00
niggl 02003ec80e feat(donations): Donations reactive create and load into datatable 2023-04-19 17:21:24 +02:00
niggl 133470b6f2 feat(donationsoverview): Switched donations overview to datatable 2023-04-19 17:12:04 +02:00
niggl 4a6230c439 Merge branch 'dev' of git.odit.services:lfk/frontend into dev
continuous-integration/drone/push Build is failing
2023-04-19 16:56:23 +02:00
niggl fdc7d80bbf 🚀RELEASE v1.2.0 2023-04-19 16:56:09 +02:00
niggl 352551e168 feat(donorsoverview): Dynamicly add newly generated donors 2023-04-19 16:55:14 +02:00
niggl 7aec050419 feat(donorsoverview): Implemented delete confirmation with datatable 2023-04-19 16:49:54 +02:00
philipp 4289034436 new license file version [CI SKIP] 2023-04-19 14:45:02 +00:00
philipp 8f8858f100 feat(DonationsOverview): i18n loading text
continuous-integration/drone/push Build is passing
2023-04-19 16:44:39 +02:00
niggl d98fb0d5b2 feat(donoroverview): Added datatable formatters 2023-04-19 16:39:30 +02:00
niggl 5014bf5bc5 feat(donors): Load donors paginated 2023-04-19 16:23:00 +02:00
niggl 0708cabc75 🚀RELEASE v1.1.0
continuous-integration/drone/push Build is failing
2023-04-19 16:05:21 +02:00
niggl 4fcb26cf93 feat(dashboard): Updated stats icons 2023-04-19 16:04:02 +02:00
niggl 269def20d1 feat(dashboard): Added average sponsoring
continuous-integration/drone/push Build is failing
2023-04-19 15:59:45 +02:00
niggl b8de9e0e42 feat(dashboard): Added average distance 2023-04-19 15:57:46 +02:00
niggl 7b2b598588 feat(dashboard): Added total donations 2023-04-19 15:56:21 +02:00
niggl e0b61486b0 feat(dashboar): Added total donors to overview 2023-04-19 15:54:39 +02:00
niggl 3f86f7412f Lockfile 2023-04-19 15:53:33 +02:00
niggl 6454d960de Bumped client 2023-04-19 15:53:28 +02:00
niggl 37154c188b Merge branch 'dev' of git.odit.services:lfk/frontend into dev
continuous-integration/drone/push Build is failing
2023-04-19 15:38:15 +02:00
niggl 8da7578a0a 🚀RELEASE v1.0.0 2023-04-19 15:37:56 +02:00
niggl 2a64094006 new license file version [CI SKIP] 2023-04-19 13:37:32 +00:00
niggl e9ce9644ff Merge pull request 'feature/175-request_pagination' (#176) from feature/175-request_pagination into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #176
2023-04-19 13:37:16 +00:00
niggl 52439aa5bc Allways set loaded to true
ref #175
2023-04-18 20:47:42 +02:00
niggl ccf865687b Donation paginated loading
ref #175
2023-04-18 20:46:18 +02:00
niggl cac34db1fd Paginated scan loading
ref #175
2023-04-18 20:43:04 +02:00
niggl faf3893180 Paginated runner loading (1000 per page)
ref #175
2023-04-18 20:40:28 +02:00
niggl c33dfcfddd Implemented Async loading of cards via pagination (500 cards per request)
ref #175
2023-04-18 20:38:01 +02:00
niggl 019e14ab1f Bumped lfk client
continuous-integration/drone/push Build is failing
2023-04-18 20:18:46 +02:00
niggl b5790196c6 Merge branch 'dev' of git.odit.services:lfk/frontend into dev
continuous-integration/drone/push Build is failing
2023-04-17 17:56:42 +02:00
niggl 94a64ca690 🚀RELEASE v0.19.0 2023-04-17 17:56:34 +02:00
niggl a6ce04c903 new license file version [CI SKIP] 2023-04-17 15:56:08 +00:00
niggl 165c154233 Merge pull request 'feature/173-scanstation_configcodes' (#174) from feature/173-scanstation_configcodes into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #174
2023-04-17 15:55:53 +00:00
niggl 318547db46 Adjusted size on smaller devices
ref #173
2023-04-17 17:55:33 +02:00
niggl e60c09e19c I18n
ref #173
2023-04-17 17:52:05 +02:00
niggl 4834d1484c Styling
ref #173
2023-04-17 17:51:46 +02:00
niggl 4b6342727e Implemented config code generation
ref #173
2023-04-17 17:47:57 +02:00
niggl cb5fa52cd9 Barcode placeholder
ref #173
2023-04-17 17:32:42 +02:00
niggl 947d01cf7f Lockfile 2023-04-17 17:32:31 +02:00
niggl 3563394fb3 Added bwip-js for barcode generation
ref #173
2023-04-17 17:32:16 +02:00
niggl 269d7a7def 🚀RELEASE v0.18.4
continuous-integration/drone/push Build is failing
2023-04-15 23:32:08 +02:00
niggl e95f2333b0 Hide address2 in orgs by default 2023-04-15 23:30:46 +02:00
niggl 950217e0a3 🚀RELEASE v0.18.3
continuous-integration/drone/push Build is failing
2023-04-15 23:27:36 +02:00
niggl 5e65fb3301 Dont show adress 2 in runner overview 2023-04-15 23:27:19 +02:00
niggl 2a294cde04 🚀RELEASE v0.18.2
continuous-integration/drone/push Build is passing
2023-04-15 19:58:14 +02:00
niggl e95420d79c Push in releaseit 2023-04-15 19:57:59 +02:00
niggl cffbd17dc7 Added timestamps to scanoverview 2023-04-15 19:56:55 +02:00
niggl 00de8c3d75 🚀RELEASE v0.18.1
continuous-integration/drone/push Build is failing
2023-04-15 19:44:17 +02:00
niggl 1f4711d07a Merge branch 'dev' of git.odit.services:lfk/frontend into dev
continuous-integration/drone/push Build is failing
2023-04-15 19:43:12 +02:00
niggl 30e3396897 Missing scanstation translations 2023-04-15 19:43:06 +02:00
philipp 5291e049a1 fix(ConfirmStatsClientDeletion): ScanStationService -> StatsClientService
continuous-integration/drone/push Build is failing
2023-04-15 19:42:19 +02:00
philipp 08fbb504c9 fix(ConfirmScanStationDeletion): donorControllerRemove -> scanStationControllerRemove 2023-04-15 19:41:42 +02:00
niggl e9ca1d3e5d Merge branch 'dev' of git.odit.services:lfk/frontend into dev
continuous-integration/drone/push Build is passing
2023-04-12 21:36:33 +02:00
niggl eb80406fdb 🚀RELEASE v0.18.0 2023-04-12 21:36:26 +02:00
philipp 9fe53b0b9c fix: button onclick a11y
continuous-integration/drone/push Build is failing
2023-04-12 21:36:16 +02:00
niggl 9ae5e62e5d Module 2023-04-12 21:36:10 +02:00
niggl 1613ae7de6 Versionbuilder 2023-04-12 21:35:32 +02:00
niggl ed1caa7be7 new license file version [CI SKIP] 2023-04-12 19:32:09 +00:00
niggl d88f3a5a27 Merge pull request 'experiment/tanstack' (#172) from experiment/tanstack into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #172
2023-04-12 19:31:47 +00:00
philipp c98eb49ae3 drop legacy dependencies 2023-04-12 21:31:25 +02:00
niggl 6d9d8a4724 Scans deletion 2023-04-12 21:25:33 +02:00
niggl 7d8c68a455 Scan deletion 2023-04-12 21:25:26 +02:00
niggl 8f33640bec Reactivated generate cards modal 2023-04-12 21:20:56 +02:00
niggl f89023e24a Always load bulk created cards 2023-04-12 21:17:53 +02:00
niggl f5d14f2e18 Scan reactive add 2023-04-12 21:14:37 +02:00
niggl 9811ede3b2 removed unused import 2023-04-12 21:11:56 +02:00
niggl b2e51fea48 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 21:11:08 +02:00
niggl 2a915620c9 Import add to datatable 2023-04-12 21:11:06 +02:00
philipp 526688935f Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 21:10:51 +02:00
philipp c7dcf7c66d scan delete working 2023-04-12 21:10:36 +02:00
niggl 06411dc147 Add runners reactivity 2023-04-12 21:09:40 +02:00
niggl 195d182cc9 Add Card appends current cards 2023-04-12 21:04:29 +02:00
philipp 17217dae76 Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 20:54:33 +02:00
philipp f105cc0a41 wip: delete scans 2023-04-12 20:54:09 +02:00
niggl 2f62c7ae89 Fixed killing of the dom 2023-04-12 20:54:00 +02:00
niggl f6c1fea17c Added status filter function 2023-04-12 20:47:36 +02:00
niggl 178dc93319 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 20:43:09 +02:00
niggl 8ffe8eff06 Basic card delete modal 2023-04-12 20:43:08 +02:00
philipp bd4952ee57 wip:ScanValid badge 2023-04-12 20:40:04 +02:00
philipp 4b171fd04f ScansOverview: use CardRunner link 2023-04-12 20:36:56 +02:00
niggl 2c198cfde8 Added custom filter to scan overview 2023-04-12 20:33:30 +02:00
niggl 7c6d39b5fa Added custom runner filter 2023-04-12 20:32:24 +02:00
philipp 9c13b2f9e9 fix(CardsOverview): table scroll + checkbox posititioning 2023-04-12 20:27:12 +02:00
philipp 1ec9556aa6 ScansOverview: fallback for manual scans 2023-04-12 20:22:59 +02:00
niggl adec38b50b Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 20:20:31 +02:00
niggl a35af6f020 Moved data loading to onmount 2023-04-12 20:20:30 +02:00
philipp e74ff5e885 Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 20:20:10 +02:00
philipp c87561f63b wip: ScansOverview -> new datatable 2023-04-12 20:19:48 +02:00
niggl c681570134 Fixed edit dispatch 2023-04-12 20:15:43 +02:00
niggl 53b945c72f Moved update card logic to overview 2023-04-12 20:14:04 +02:00
niggl f6985daec7 Cards details modal 2023-04-12 20:07:46 +02:00
niggl 5662c3b6da Basic card table replace 2023-04-12 20:06:26 +02:00
philipp 9def0b27c9 fix: formatting 2023-04-12 19:56:29 +02:00
niggl 52a02c82d2 yeeted extra table styling 2023-04-12 19:47:48 +02:00
niggl c241961d0a Extracted table header 2023-04-12 19:46:33 +02:00
niggl 8f50555a06 Extracted table bottom 2023-04-12 19:44:48 +02:00
philipp b35375c929 fix min-w th 2023-04-12 19:43:15 +02:00
philipp bf1e715261 RunnersOverview: table responsiveness 2023-04-12 19:41:41 +02:00
niggl 0240e1dca2 import 2023-04-12 19:36:35 +02:00
niggl 7cec2a00c5 Fixed id sorting 2023-04-12 19:34:54 +02:00
niggl 239f79fecb Moved code around 2023-04-12 19:28:10 +02:00
philipp 0265a59b82 Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 19:26:56 +02:00
philipp 57dce34fc5 fix: table sort button + search style 2023-04-12 19:26:54 +02:00
niggl d8110580e9 Added middle-name 2023-04-12 19:25:33 +02:00
niggl 03b7ada5ef Close modal on delete and import toastify 2023-04-12 19:23:27 +02:00
philipp 1df505ea00 fix(DeleteRunnerModal): ESC key 2023-04-12 19:22:52 +02:00
niggl 3e8dac3203 Reload table data on delete 2023-04-12 19:22:26 +02:00
niggl 95707a71a9 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 19:21:19 +02:00
niggl fc2c2907c4 Disable sort for actions 2023-04-12 19:21:01 +02:00
philipp ebdd1c2c0c quick cleanup 2023-04-12 19:20:03 +02:00
niggl 13254b24dd Fixed styling 2023-04-12 19:15:28 +02:00
niggl e17eb64031 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 19:14:44 +02:00
niggl a0727a0291 Extracted deletion into function of overview 2023-04-12 19:14:42 +02:00
philipp f7f7926829 Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 19:11:13 +02:00
philipp 9b7dca341b Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 19:11:08 +02:00
niggl da3300562a Delete modal logic 2023-04-12 19:11:07 +02:00
niggl e2ddb5a14c Added delete toast 2023-04-12 19:05:57 +02:00
philipp fb9645aed6 Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 19:05:02 +02:00
niggl a4ebc7e126 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 19:04:22 +02:00
niggl fd5db7d68a Added delete runner modal 2023-04-12 19:04:15 +02:00
philipp e7eddb4f08 drop redundant button role 2023-04-12 19:03:49 +02:00
philipp 94155845f0 RunnersOverview: add filter keyboard support 2023-04-12 19:00:10 +02:00
philipp 3abf608b15 improved tablefilters/groupFilter 2023-04-12 18:56:55 +02:00
niggl d31fe2363b ammendme 2023-04-12 18:51:48 +02:00
niggl 11a56f87e8 Implemented table buttons 2023-04-12 18:51:42 +02:00
niggl 19793cdcd4 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 18:47:52 +02:00
niggl 9363773fa1 Basic details and delete buttons 2023-04-12 18:47:47 +02:00
philipp c7990882cf fix: TracksOverview 2023-04-12 18:46:31 +02:00
philipp d4ab76ea1b RunnersOverview: pass selectedRunners to actions 2023-04-12 18:42:16 +02:00
philipp 2c992a0e63 RunnersOverview: disable debug log 2023-04-12 18:37:38 +02:00
philipp 88f96acc3c RunnersOverview: TopActionSection: add margin top 2023-04-12 18:37:26 +02:00
philipp 245db06173 updated default table row count 2023-04-12 18:37:02 +02:00
philipp 49c2cd5c4b show certificate, runnercard, sponsoring contract section 2023-04-12 18:36:49 +02:00
philipp 64db553185 fix: checkbox styling 2023-04-12 18:31:43 +02:00
philipp a06a19ce9c Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 18:29:25 +02:00
philipp 592ddc1541 Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 18:29:15 +02:00
philipp cb5f2b73d0 drop old datatables 2023-04-12 18:29:06 +02:00
niggl 2304b12c1c Moved filter function to shared 2023-04-12 18:28:48 +02:00
niggl 38d3e1912c Unused filter function value 2023-04-12 18:26:36 +02:00
niggl fbc14fd7b4 Make the linter happy 2023-04-12 16:31:56 +02:00
niggl 0283df22c8 Group filters 2023-04-12 16:30:00 +02:00
philipp 845737ee8e Merge branch 'experiment/tanstack' of https://git.odit.services/lfk/frontend into experiment/tanstack 2023-04-12 16:18:55 +02:00
philipp 6993511c67 feat(RunnersOverview): row selection 2023-04-12 16:18:45 +02:00
niggl 9111ad147c Updated group name conversion 2023-04-12 16:14:06 +02:00
niggl 333214aa8f Added distance conversion 2023-04-12 16:09:57 +02:00
niggl c0cde02fec Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 16:06:58 +02:00
niggl 070a20a2e5 Table header i18n 2023-04-12 16:06:55 +02:00
philipp c5e8409079 add basic table styling 2023-04-12 16:05:42 +02:00
niggl 67eff0eda9 Dsable column filter for distance 2023-04-12 16:03:53 +02:00
niggl 3de7b632e0 Moved sort onclick to header only 2023-04-12 16:03:20 +02:00
niggl 842248e4c4 Added sort 2023-04-12 16:02:00 +02:00
niggl c5d7ec25b5 Merge branch 'experiment/tanstack' of git.odit.services:lfk/frontend into experiment/tanstack 2023-04-12 15:58:33 +02:00
niggl a9a965d698 Added filterfunctions 2023-04-12 15:58:31 +02:00
philipp dc866dd540 default to 50 rows pagination 2023-04-12 15:58:13 +02:00
niggl 89252619b1 Yeeted old datatable references 2023-04-12 15:56:53 +02:00
niggl 2699b06d7c Filter id as equals 2023-04-12 15:54:36 +02:00
philipp fd0d45f721 debug table 2023-04-12 15:52:19 +02:00
philipp 5ecf838dd2 cleanup headers 2023-04-12 15:52:13 +02:00
philipp 45a7a90cb8 pagination size 2023-04-12 15:52:05 +02:00
philipp cac851f2b1 fix pagination next prev 2023-04-12 15:51:46 +02:00
niggl 238082b657 getPaginationRowModel 2023-04-12 15:48:08 +02:00
niggl aecbabe522 -> onkeyup 2023-04-12 15:43:52 +02:00
niggl a9cdac4f74 Added filter 2023-04-12 15:40:43 +02:00
philipp a59dbbe50e wip: pagination 2023-04-12 15:36:45 +02:00
philipp 9bec95ede8 dependency update, drop focusTrap, first tanstack experiment in RunnersOverview 2023-04-12 15:20:38 +02:00
niggl 70307a9e82 Added delete cards button
continuous-integration/drone/push Build is passing
ref #161
2023-04-12 14:34:06 +02:00
niggl ef077b4e6a Cards deleted migrations
ref #161
2023-04-12 14:32:55 +02:00
niggl dcabed4e93 Added translations
ref #161
2023-04-12 14:30:35 +02:00
niggl 1af047f66e Moved filter function to typed version
continuous-integration/drone/push Build is passing
closes #171
2023-04-12 14:16:36 +02:00
niggl ee91748b3c Bumped pnpm to 8
continuous-integration/drone/push Build is passing
2023-03-29 19:50:52 +02:00
niggl e5241d619b No longer switching pnpm store path
continuous-integration/drone/push Build is failing
2023-03-29 19:48:02 +02:00
niggl d79608edbb Switched drone to pnpm cache
continuous-integration/drone/push Build is failing
2023-03-29 19:46:49 +02:00
niggl 4cbd26580e Moved docker to pnpm with cache 2023-03-29 19:45:35 +02:00
niggl fe62ad5539 ignore pnpm store from now on
continuous-integration/drone/push Build is passing
2023-03-29 19:44:06 +02:00
niggl eb13f038a1 Removed pnpm store 2023-03-29 19:43:16 +02:00
philipp 9505c2b030 add TODO for ScansOverview status filter
continuous-integration/drone/push Build is passing
2023-03-19 12:45:07 +01:00
philipp 008835c24f ScansOverview: add ThFilterTrack
continuous-integration/drone/push Build is passing
2023-03-19 12:38:09 +01:00
philipp 7083b3d8d2 card/ThFilterRunner: text align left 2023-03-19 12:29:23 +01:00
philipp 754931b2f6 ScansOverview: migrate to datatable
continuous-integration/drone/push Build is passing
close #168
2023-03-19 12:28:27 +01:00
philipp 2dc8ffba32 Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
continuous-integration/drone/push Build is passing
2023-03-15 15:05:29 +01:00
philipp d0fe6a2e85 new license file version [CI SKIP] 2023-03-15 14:05:18 +00:00
philipp 85705b6e68 🚀RELEASE v0.17.3 2023-03-15 15:05:14 +01:00
philipp 3ea7a015a9 dependency fixes
continuous-integration/drone/push Build is passing
2023-03-15 15:04:55 +01:00
philipp 44329413ed set pnpm to @7 2023-03-15 15:02:54 +01:00
philipp 46db68ab22 🚀RELEASE v0.17.2 2023-03-15 14:53:48 +01:00
philipp dc9d7f22a2 Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
continuous-integration/drone/push Build is failing
2023-03-15 14:47:32 +01:00
philipp f917018fd9 improved ThFilterGroup style 2023-03-15 14:47:27 +01:00
philipp 7b420c430d 🚀RELEASE v0.17.1 2023-03-15 14:44:26 +01:00
philipp 00359d25c1 new license file version [CI SKIP] 2023-03-15 13:43:57 +00:00
philipp d8a3063735 Revert "package dependency fixes, bumps, lockfile update"
continuous-integration/drone/push Build is failing
This reverts commit 2c73b9862d.
2023-03-15 14:43:33 +01:00
niggl 6491af19e3 🚀RELEASE v0.17.0
continuous-integration/drone/push Build is passing
2023-03-15 13:35:48 +01:00
niggl 61328d20ed new license file version [CI SKIP] 2023-03-15 12:34:41 +00:00
niggl 0a6d92a1f3 Switched license generation to cache registry and pnpm
continuous-integration/drone/push Build is passing
2023-03-15 13:34:14 +01:00
niggl 3a576d1073 Pinned pnpm in dockerfile, thx @philipp
continuous-integration/drone/push Build is failing
2023-03-15 13:29:33 +01:00
niggl b30b98b521 Pinned ci node version 2023-03-15 13:25:59 +01:00
niggl 43d82a2af0 Fixed pnpm being called without being installed
continuous-integration/drone/push Build is failing
2023-03-15 13:18:07 +01:00
philipp 6a4495b813 Merge pull request 'bugfix/162-create_card_modal' (#163) from bugfix/162-create_card_modal into dev
continuous-integration/drone/push Build is failing
Reviewed-on: #163
2023-03-15 12:15:24 +00:00
niggl e8a0ad6647 You can now create cards from runners by searching via #runnerid
ref #162
2023-03-15 13:12:42 +01:00
niggl 92b89cc4d8 Fixed double space in label
ref #162
2023-03-15 13:09:07 +01:00
niggl 268b1b1d98 Removed unused log
ref #162
2023-03-15 13:07:49 +01:00
niggl 75bc89ca30 Fixed runners not showing up
ref #162
2023-03-15 13:06:56 +01:00
philipp 0625937068 Merge pull request 'filter by runner full names + "#<ID>"' (#160) from feature/159-cardsoverview-filter-for-runner-full-names-and-id into dev
continuous-integration/drone/push Build is failing
Reviewed-on: #160
2023-03-15 11:20:05 +00:00
niggl 32a9074963 Wow this api is fun
ref #159
2023-03-15 12:14:39 +01:00
niggl b869b5fd2a remodelled for early return
ref #159
2023-03-15 11:39:51 +01:00
philipp 3a3e2f7157 add ThFilterRunner
ref #159
2023-03-15 11:10:08 +01:00
philipp bea57aa03a fix styling for table filters th border
continuous-integration/drone/push Build is failing
2023-03-15 11:08:05 +01:00
philipp 30991d5364 UsersOverview: drop pfp
continuous-integration/drone/push Build is failing
2023-03-14 09:53:16 +01:00
philipp 5cc8b0811c UsersOverview: change profilepic scaling
continuous-integration/drone/push Build is failing
2023-03-14 09:51:40 +01:00
philipp 2c73b9862d package dependency fixes, bumps, lockfile update
continuous-integration/drone/push Build is failing
2023-03-14 09:51:23 +01:00
philipp 732b2f061e wip: pnpm + node version 2023-03-14 09:29:27 +01:00
philipp 3680533eef 🚀RELEASE v0.16.5
continuous-integration/drone/push Build is passing
2023-03-14 09:25:11 +01:00
philipp 1307d72c9d Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
continuous-integration/drone/push Build is failing
2023-03-14 09:24:54 +01:00
philipp 405dfa0c34 new license file version [CI SKIP] 2023-03-14 08:24:37 +00:00
philipp 5c2d154ad1 🚀RELEASE v0.16.4 2023-03-14 09:24:31 +01:00
philipp f2bf8d9bac fix: OrgDetail: clicking on address will toggle selfservice
continuous-integration/drone/push Build is passing
close #158
2023-03-14 09:23:55 +01:00
niggl f9cfd6bd06 🚀RELEASE v0.16.3
continuous-integration/drone/push Build is passing
2023-02-23 14:01:35 +01:00
niggl 287f63fa52 Merge branch 'dev' of git.odit.services:lfk/frontend into dev
continuous-integration/drone/push Build is passing
2023-02-23 14:00:20 +01:00
niggl 5fe47634e8 Bumped vite build targets 2023-02-23 13:59:27 +01:00
niggl a6590910cf new license file version [CI SKIP] 2023-02-23 12:54:38 +00:00
niggl ad454c386c Merge pull request 'feature/156-pdf_names' (#157) from feature/156-pdf_names into dev
continuous-integration/drone/push Build is failing
Reviewed-on: #157
2023-02-23 12:54:04 +00:00
niggl 0b2c296de0 Added ids for generated pdfs
ref #156
2023-02-23 09:59:07 +01:00
niggl 0e85940cba 🚀RELEASE v0.16.2
continuous-integration/drone/push Build is passing
2023-02-23 08:36:54 +01:00
niggl 8d479c32f8 Merge pull request 'feature/147-cardoverview_performance' (#153) from feature/147-cardoverview_performance into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #153
2023-02-23 07:34:46 +00:00
niggl 549785cf7d Merge pull request 'Fixed scanmodal' (#155) from bugfix/154-scan_select_runner_by_id into dev
continuous-integration/drone/push Build is failing
Reviewed-on: #155
2023-02-23 07:34:39 +00:00
niggl aafc4c8d62 Removed unused console log
ref #154
2023-02-22 18:39:41 +01:00
niggl 47dedbdc73 Fixed scanmodal
fixes #154
2023-02-22 18:38:21 +01:00
niggl 6fe134afc8 i18n import
ref #147
2023-02-22 18:33:42 +01:00
niggl 63a50f92e7 Merge branch 'feature/147-cardoverview_performance' of git.odit.services:lfk/frontend into feature/147-cardoverview_performance 2023-02-22 18:32:29 +01:00
niggl ca6da15ef7 i18n
ref #147
2023-02-22 18:32:25 +01:00
niggl 8dfa19fa0f Fixed all filter
ref #147
2023-02-22 18:31:36 +01:00
niggl 0feee0ae2f Fixed edit update bug
ref #147
2023-02-22 18:06:53 +01:00
philipp 2a6a39916a rename: ThFilterGroup -> ThFilterStatus
ref #147
2023-02-19 15:14:09 +01:00
niggl f0a2b2859f Added custom status filter 2023-02-18 19:27:13 +01:00
niggl 32ddb66fc8 Trigger edit modal 2023-02-18 19:24:28 +01:00
niggl df63c2388d Added old formatting for runner and status
ref #147
2023-02-18 19:22:42 +01:00
niggl 757655ea63 Bsic datatable conversion
ref #147
2023-02-18 19:20:29 +01:00
philipp 329c1cc037 Merge pull request 'fix: RunnerDetail: set .phone to null if empty' (#152) from bugfix/151-runnerdetail--cannot-unset-phone-number into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #152
2023-02-18 16:37:56 +00:00
philipp da6dd55d13 set .phone to null if empty 2023-02-18 17:30:01 +01:00
philipp 0e5490f1c8 new license file version [CI SKIP] 2023-02-18 16:18:28 +00:00
philipp b82d638de1 Merge pull request 'feature/146-runner-table-performance-data-table' (#150) from feature/146-runner-table-performance-data-table into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #150
2023-02-18 16:17:51 +00:00
philipp 224034dcc6 fix: z-index on action buttons 2023-02-18 17:17:04 +01:00
philipp 026d3d41c1 new license file version [CI SKIP] 2023-02-18 16:13:06 +00:00
philipp fd1a06b359 Merge pull request 'feature/148-dashboard_statscards' (#149) from feature/148-dashboard_statscards into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #149
2023-02-18 16:12:30 +00:00
niggl 452d010183 Updated breakpoints
ref #148
2023-02-18 16:27:58 +01:00
niggl eb1c17e3ac Dasboard Cards redesign 2023-02-18 16:24:13 +01:00
niggl a101873eb0 Tailwind bump
ref #148
2023-02-18 16:24:02 +01:00
niggl 3d2acb692a Fixed top checkbox state 2023-02-18 15:53:47 +01:00
niggl 0900c2691e Fixed checkbox show 2023-02-18 15:52:59 +01:00
niggl 1337676e08 Basic checkbox fix 2023-02-18 15:49:24 +01:00
philipp 2e075eafab RunnersOverview loading fix
ref #146
2023-02-16 15:43:11 +01:00
philipp 14d64b6070 add group filtering to table
ref #146
2023-02-16 15:05:41 +01:00
philipp 81b8fbf4e3 1st datatable try with @vincjo/datatables 2023-02-16 12:27:45 +01:00
philipp 24d074752f formatting 2023-02-16 11:48:30 +01:00
philipp 08047a9307 cleaned up table search 2023-02-16 11:47:59 +01:00
philipp 1b0cd5b90b improved runner search 2023-02-16 11:45:38 +01:00
philipp 65e8998894 set table-layout:fixed + display when loaded
ref #146
2023-02-16 11:26:37 +01:00
philipp 449948050b 🚀RELEASE v0.16.1
continuous-integration/drone/push Build is passing
2023-02-15 15:05:33 +01:00
philipp cf97281592 fix: donor detail: sponsorings: unset middlename will show as "null"
continuous-integration/drone/push Build is passing
close #145
2023-02-15 15:05:01 +01:00
philipp 75684efa1a 🚀RELEASE v0.16.0
continuous-integration/drone/push Build is passing
2023-02-03 14:07:27 +01:00
philipp 2c4f27a943 new license file version [CI SKIP] 2023-02-03 13:05:38 +00:00
philipp 53b7dec7cd Merge pull request 'feature/143-beamershow_clients' (#144) from feature/143-beamershow_clients into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #144
2023-02-03 13:05:01 +00:00
niggl e0cbfb000b Tailwind bump 2023-02-02 17:27:18 +01:00
niggl 3a66f4c862 new license file version [CI SKIP] 2023-02-02 16:23:56 +00:00
niggl 85ceaa464f Merge branch 'dev' into feature/143-beamershow_clients 2023-02-02 17:23:33 +01:00
niggl 976755338b Updated docker base images
continuous-integration/drone/push Build is failing
2023-02-02 17:21:58 +01:00
niggl 1c980059cf Switched drone to kaniko 2023-02-02 17:20:01 +01:00
niggl 2d8c4c1698 Ignore pnpm lock 2023-02-02 17:19:51 +01:00
niggl 19a333d7bd Added missing translation
ref #143
2023-02-02 17:16:24 +01:00
niggl 96c55db63d Added translation
ref #143
2023-02-02 17:13:16 +01:00
niggl fecb07ee37 Re-added copy modal
ref #143
2023-02-02 17:11:46 +01:00
niggl e10c6480a5 Removed Key after creation
ref #143
2023-02-02 17:08:29 +01:00
niggl f3cc07c009 Fixed imports and naming 2023-02-02 17:05:34 +01:00
niggl 068076dd47 Added Statsclients to sidebar
ref #143
2023-02-02 17:03:18 +01:00
niggl 02158605be Basic statsclient detail
ref #143
2023-02-02 17:00:49 +01:00
niggl 674e6a90ec Updated mounted variables 2023-02-02 16:54:37 +01:00
niggl f679330466 Updated Add modal
ref #143
2023-02-02 16:51:39 +01:00
niggl 93fc7c2e83 Updated deletion modal
ref #143
2023-02-02 16:46:18 +01:00
niggl f299617c60 First page for statsclients
ref #143
2023-02-02 16:42:17 +01:00
niggl 28cbc5b98c Bumped apiclient
ref #143
2023-02-02 16:21:11 +01:00
niggl c28f1ee0bc Bumped apiclient
ref #143
2023-02-02 16:04:21 +01:00
niggl cff112d705 Pinned versions
continuous-integration/drone/push Build is failing
2023-02-02 16:02:52 +01:00
niggl 9fc4ad63c4 🚀RELEASE v0.15.6
continuous-integration/drone/push Build is passing
2021-07-19 17:52:02 +02:00
niggl 97054a71c1 new license file version [CI SKIP] 2021-07-19 15:49:32 +00:00
niggl 2391668a25 Fixed donations getting reduced to the first one on certificates
continuous-integration/drone/push Build is passing
2021-07-19 17:47:27 +02:00
niggl 717d33547c 🚀RELEASE v0.15.5
continuous-integration/drone/push Build is passing
2021-07-05 17:23:43 +02:00
niggl 997be32679 Merge pull request 'Fixed kilometer conversion' (#142) from bugfix/141-runner_kilometers into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #142
2021-07-05 15:22:55 +00:00
niggl 134f00c40e Fixed kilometer conversion
ref #141
2021-07-05 17:15:50 +02:00
philipp 47c898bdfd Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
continuous-integration/drone/push Build is passing
2021-07-05 17:01:59 +02:00
philipp e752ee12d1 new license file version [CI SKIP] 2021-07-05 15:01:42 +00:00
philipp cc4515ff66 🚀RELEASE v0.15.4 2021-07-05 17:01:31 +02:00
philipp f190292171 Merge pull request 'fix total donation sum in dashboard' (#140) from bugfix/139-total-donation-sum-is-wrong into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #140

close #139
2021-07-05 15:00:44 +00:00
philipp b246f2b349 divide by 100 + toFixes(2)
ref #139
2021-07-05 13:30:17 +02:00
niggl 76b69d851a 🚀RELEASE v0.15.3
continuous-integration/drone/push Build is passing
2021-04-16 18:22:27 +02:00
niggl 224f586368 Small bugfix (null got displayed) 🛠 2021-04-16 18:22:00 +02:00
philipp 9add6c8ff1 🚀RELEASE v0.15.2
continuous-integration/drone/push Build is passing
2021-04-16 18:10:50 +02:00
philipp 7a63d4eed1 Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
continuous-integration/drone/push Build is passing
2021-04-16 18:09:37 +02:00
philipp e54a4807f7 NGINX cache assets 2021-04-16 18:09:30 +02:00
philipp cee04c1d6f Footer - noopener link 2021-04-16 18:09:22 +02:00
niggl cbec78589d Hotfix: Team change recognition 🐞
continuous-integration/drone/push Build is passing
2021-04-16 18:06:53 +02:00
niggl a85db7cb3f 🚀RELEASE v0.15.1
continuous-integration/drone/push Build is passing
2021-04-16 17:53:38 +02:00
niggl 2bd3779839 Merge pull request '🐞🐳 fix Dockerfile' (#138) from bugfix/136-opacity_reactivity into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #138
2021-04-16 15:51:37 +00:00
philipp 303e33cafb 🐞🐳 fix Dockerfile
ref #136
2021-04-16 17:46:15 +02:00
niggl b4e689dddf Dockerfile now uses selfhosted registry
continuous-integration/drone/push Build is passing
2021-04-15 19:50:37 +02:00
niggl 98a0b036c5 new license file version [CI SKIP] 2021-04-15 17:46:04 +00:00
niggl fb3f30fb10 Merge pull request 'Opacity import fix bugfix/136-opacity_reactivity' (#137) from bugfix/136-opacity_reactivity into dev
continuous-integration/drone/push Build is failing
Reviewed-on: #137
2021-04-15 17:44:49 +00:00
niggl 6213952007 Added bs import fix
ref #136
2021-04-15 19:43:43 +02:00
philipp 07ac041d69 🚚 move to tailwind
ref #136
2021-04-15 19:22:57 +02:00
niggl 5c02028841 🚀RELEASE v0.15.0
continuous-integration/drone/push Build is passing
2021-04-15 18:30:38 +02:00
niggl c561b53670 Merge pull request 'Mark donations as payed feature/133-donation_payments' (#135) from feature/133-donation_payments into dev
continuous-integration/drone/push Build is failing
Reviewed-on: #135
2021-04-15 16:29:39 +00:00
philipp dcd0d5a362 Merge branch 'feature/133-donation_payments' of https://git.odit.services/lfk/frontend into feature/133-donation_payments 2021-04-15 18:27:47 +02:00
philipp 18acac83bc AddDonationModal - vertical alignment for paid status
ref #133
2021-04-15 18:27:35 +02:00
philipp d7d44470bb DonationsOverview contrast on action
ref #133
2021-04-15 18:25:52 +02:00
niggl 0f0aae7ba4 Fixed chante recognition bug for fixed donation
ref #133
2021-04-15 18:21:23 +02:00
niggl 4c0886a5d9 Fixed typo
ref #133
2021-04-15 18:04:03 +02:00
niggl 04a3038369 Added missing updated comparison
ref #133
2021-04-15 16:56:03 +02:00
niggl bdcf5d3fc0 Added payment updating via detail
ref #133
2021-04-15 15:54:14 +02:00
niggl c7a858eed7 Sorted translations
ref #133
2021-04-15 15:42:47 +02:00
niggl de5aa9237d Added **all** missing toast translations
ref #133
2021-04-15 15:42:29 +02:00
niggl d015f97395 Added translations 🌎
ref #113
2021-04-15 15:34:36 +02:00
niggl 57618156b4 Added msiisng runner id conversion
ref #133
2021-04-15 15:30:23 +02:00
niggl 865254d646 Fixed styling
ref #133
2021-04-15 15:25:17 +02:00
niggl 1dbab03fe7 You can now add payments from the donation overview
ref #133
2021-04-15 15:24:31 +02:00
niggl a943aaf5fc You can now open a modal to add a payment to a donation from the donation overview
ref #133
2021-04-15 15:05:05 +02:00
niggl 6e6e8b2617 Added Add Payment button to donor overview
ref #133
2021-04-15 14:40:46 +02:00
niggl 4c2c24af2c Changed top info style for donation overview
ref #133
2021-04-15 14:33:35 +02:00
niggl 3d3a10aafb You can now mark fixed donations as already paid on creation
ref #133
2021-04-15 14:31:24 +02:00
niggl 000fc97beb Changed top info style for donation detail
ref #133
2021-04-15 14:18:28 +02:00
niggl 5645eeaafa Added paid donation amount and status to donation detail
ref #133
2021-04-15 14:17:28 +02:00
niggl 961477d522 Added total donation amount to donation overview
ref #133
2021-04-15 14:12:11 +02:00
niggl a5f71015a6 Added total donation amount to donor detail
ref #133
2021-04-15 14:10:35 +02:00
niggl e42ea943b7 Added total donation amount to donor overview
ref #133
2021-04-15 14:09:23 +02:00
philipp 9c5fc6b61c 🚀RELEASE v0.14.0
continuous-integration/drone/push Build is passing
2021-04-14 19:28:00 +02:00
philipp 302caf015f new license file version [CI SKIP] 2021-04-14 17:27:30 +00:00
philipp e11296071a Merge pull request 'added donor receipt list download to DonorsOverview' (#134) from feature/132-export-donors-receipt-list into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #134
close #132
2021-04-14 17:26:10 +00:00
niggl 112eb29f93 Switched to selfhosted images
ref #132
2021-04-14 19:24:06 +02:00
niggl c6c97516b3 Sorted translations 🌎
ref #132
2021-04-14 19:23:26 +02:00
niggl 03676b2894 Fixed typos in translations
ref #132
2021-04-14 19:23:07 +02:00
philipp 9ca57fac2e bump @odit/lfk-client-js@0.11.0
ref #132
2021-04-14 18:58:57 +02:00
philipp 18f151c1fb general version bump
ref #132
2021-04-14 18:57:14 +02:00
philipp e90e56d8b2 replace donationAmount with paidDonationAmount
ref #132
2021-04-14 18:54:05 +02:00
philipp d241ca5698 added donor receipt list download to DonorsOverview
ref #132
2021-04-14 18:43:51 +02:00
niggl b512cf8667 🚀RELEASE v0.13.1
continuous-integration/drone/push Build is passing
2021-04-11 21:14:03 +02:00
niggl a24d2923c6 For await fix
continuous-integration/drone/push Build is failing
2021-04-11 21:13:44 +02:00
niggl 467808abef 🚀RELEASE v0.13.0
continuous-integration/drone/push Build is failing
2021-04-11 21:08:58 +02:00
niggl 861f1f2216 Merge pull request 'Better org pdf generation feature/130-org_doc_splitting' (#131) from feature/130-org_doc_splitting into dev
continuous-integration/drone/push Build is failing
Reviewed-on: #131
2021-04-11 19:07:53 +00:00
niggl 509b22bea0 Org certificate generation now runs in sequence
ref #130
2021-04-11 21:00:33 +02:00
niggl 7447b2f4c1 Fixed const -> let
ref #130
2021-04-11 20:54:38 +02:00
niggl fef14b6e4f Org card generation now runs in sequence
ref #130
2021-04-11 20:53:58 +02:00
niggl 01d2a7e6aa Org contract generation now runs in sequence
ref #130
2021-04-11 20:48:20 +02:00
niggl ac586fec5a Hotfix: Org * generation🐞
continuous-integration/drone/push Build is passing
2021-04-11 20:17:34 +02:00
niggl 5476808683 Emergency document server url change
continuous-integration/drone/push Build is passing
2021-04-11 20:10:08 +02:00
niggl 331d737796 🚀RELEASE v0.12.5
continuous-integration/drone/push Build is passing
2021-04-08 19:30:20 +02:00
niggl ef81b8adf9 Merge pull request 'Added runner team's parentorg name to runenr overciew' (#129) from feature/128-runner_orgs into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #129
2021-04-08 17:29:27 +00:00
niggl 8a7d635cef Switched to html entity
ref #128
2021-04-08 18:00:47 +02:00
niggl 4c259c1eef Added runner team's parentorg name to runenr overciew
ref #128
2021-04-08 17:58:49 +02:00
philipp 5b4ede5e2f 🚀RELEASE v0.12.4
continuous-integration/drone/push Build is passing
2021-04-08 17:34:32 +02:00
philipp d0ab3dda78 🚑 [HOTFIX] - drop "svelte-infinite-loading"
continuous-integration/drone/push Build is failing
2021-04-08 17:34:04 +02:00
philipp d9cf51b4bb 🚀RELEASE v0.12.3
continuous-integration/drone/push Build is failing
2021-04-08 17:30:23 +02:00
philipp aa17f24220 new license file version [CI SKIP] 2021-04-08 15:28:50 +00:00
philipp cf60edf7d4 Merge pull request 'fix' (#126) from bugfix/125-mobile into dev
continuous-integration/drone/push Build is failing
Reviewed-on: #126
close #125
2021-04-08 15:27:22 +00:00
philipp ffbc243194 custom css fix for collapsed_navigation
ref #125
2021-04-07 21:44:29 +02:00
philipp b6b07cf30c 🐞 bugfix for svelte x tailwind class names
ref #125
2021-04-07 21:35:01 +02:00
philipp 495a6b22bd almost fixed... 2021-04-07 21:28:21 +02:00
philipp 0acaffbdfa fix
ref #125
2021-04-07 20:25:04 +02:00
niggl 6043bc4517 🚀RELEASE v0.12.2
continuous-integration/drone/push Build is failing
2021-04-07 20:11:21 +02:00
niggl e6ed066e3f Merge pull request 'feature/110-virtual_list' (#124) from feature/110-virtual_list into dev
continuous-integration/drone/push Build is failing
Reviewed-on: #124
2021-04-07 18:10:02 +00:00
niggl ee4e8655b8 Merge branch 'dev' into feature/110-virtual_list 2021-04-07 20:09:35 +02:00
philipp 37970d2be6 pre-merge fixes
ref #110
2021-04-07 18:59:46 +02:00
philipp 1376788016 updated virtual scroll list 2021-04-07 18:38:52 +02:00
philipp 4cad86cf85 fixed height table 2021-04-07 18:19:58 +02:00
philipp 6304116edb wip on virtuallist 2021-04-06 22:16:24 +02:00
niggl 834ff8fa63 🚀RELEASE v0.12.1
continuous-integration/drone/push Build is passing
2021-04-06 16:47:37 +02:00
niggl 1f428a535e Merge pull request 'ImportRunnerModal Cancel Button feature/122-import_cancel' (#123) from feature/112-import_cancel into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #123
2021-04-06 14:42:37 +00:00
niggl 0c40966970 Added cancel button for the first stage of runner import
ref #112
2021-04-05 16:23:24 +02:00
niggl 9da071fe9b Escape now triggers foll modal close (including reset) instead of just hiding th modal
ref #112
2021-04-05 16:14:43 +02:00
niggl 892a04f289 🚀RELEASE v0.12.0
continuous-integration/drone/push Build is passing
2021-04-05 16:09:17 +02:00
niggl 27cc9727f1 Fixed package version
continuous-integration/drone/push Build is passing
2021-04-05 16:08:41 +02:00
niggl f0738d451b Merge pull request 'Implmented certificate generation feature/119-Certificate_generation' (#120) from feature/119-Certificate_generation into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #120
2021-04-05 14:05:38 +00:00
niggl 9e6a8daf2c Sorted translations 🌍
ref #119
2021-04-05 16:04:44 +02:00
niggl bfacfec765 The PFS Prefixes now get translated via i18n
ref #119
2021-04-05 16:04:26 +02:00
niggl 0bae5bf32b sponsoring pdf names now include their locale
ref #119
2021-04-05 15:37:12 +02:00
niggl 22b09d16d0 Cleaned up generation strings and added the schem for single runner generations for sponsoring contracts
ref #119
2021-04-05 15:36:01 +02:00
niggl 9c867e106e Cleaned up generation strings and added the schem for single runner generations for cards
ref #119
2021-04-05 15:33:55 +02:00
niggl 304f28a3c1 certificate pdf names now include their locale
ref #119
2021-04-05 15:31:52 +02:00
niggl d65d3793de Changed the basic nameing generation for runenr certificate files
ref #119
2021-04-05 15:31:01 +02:00
niggl 3638d87bd2 Runnercard pdfs now include their locale
ref #119
2021-04-05 15:28:13 +02:00
niggl b97a92860d Fixed wrong permissiong getting checked
ref #119
2021-04-05 15:24:42 +02:00
philipp 7c86a5eeb3 added missing/ wrong translations + formatting!
ref #119
2021-04-05 12:02:18 +02:00
niggl d23dbaaf69 Removed useless console.log
ref #119
2021-04-03 20:05:27 +02:00
niggl e6ffc371e1 Certificate generation from org detail
ref #119
2021-04-03 20:03:57 +02:00
niggl 3177c6eaa3 Certificate generation from org overview
ref #119
2021-04-03 20:02:52 +02:00
niggl acd2f0519d Certificate generation from team detail
ref #119
2021-04-03 20:00:51 +02:00
niggl 18ec100c33 Certificate generation from team overview
ref #119
2021-04-03 19:59:34 +02:00
niggl fa55fce76e Merge branch 'feature/119-Certificate_generation' of git.odit.services:lfk/frontend into feature/119-Certificate_generation 2021-04-03 19:59:20 +02:00
niggl f47d5e347d Copy-paste fix
ref #119
2021-04-03 19:59:18 +02:00
niggl 7488a8b597 Copy-paste fix
ref #119
2021-04-03 19:58:24 +02:00
niggl 2e3ac154be Implemented generation for orgs
ref #119
2021-04-03 19:52:41 +02:00
niggl 2472640755 Implemented generation for teams
ref #119
2021-04-03 19:51:01 +02:00
niggl 7b685d6cad Added certificate generation from runner overview and detail
ref #119
2021-04-03 19:48:31 +02:00
niggl 17f6f4e616 Added i18n
ref #119
2021-04-03 19:46:17 +02:00
niggl 48cfc15cfb Removed useless console log
ref #119
2021-04-03 19:44:57 +02:00
niggl bb9b779cee You can now generate certificates from the runner overview
ref #119
2021-04-03 19:44:26 +02:00
niggl af63ce67ae Added basic certificate generation component
ref #119
2021-04-03 19:38:54 +02:00
philipp 5cc4871ec4 new license file version [CI SKIP] 2021-04-03 17:18:28 +00:00
philipp c8cfe669b8 Merge pull request 'feature/108_vite_migration' (#118) from feature/108_vite_migration into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #118
close #108
2021-04-03 17:17:23 +00:00
philipp 8b74d6d759 bump @odit/lfk-client-js@0.10.1
ref #108
2021-04-03 19:16:53 +02:00
philipp a9227768de 🐞 fix await for esNext
ref #108
2021-04-03 19:13:05 +02:00
philipp d966e1d4de Merge branch 'dev' into feature/108_vite_migration
# Conflicts:
#	index.html
#	package.json
#	public/licenses.json
#	src/App.svelte
#	src/components/orgs/OrgOverview.svelte
#	src/components/teams/TeamsOverview.svelte
2021-04-03 19:10:10 +02:00
philipp ceb2146c1b 🔨 dev container open
ref #108
2021-04-03 18:31:03 +02:00
philipp 8d006d8c74 version bump: vite-plugin-windicss@0.12.2
ref #108
2021-04-03 18:22:00 +02:00
philipp 777304f259 🔨🔥 alpine based devcontainer with working yarn PnP
ref #108
2021-04-02 21:57:56 +02:00
philipp 12433f7c23 🧹 reorder + fix package
ref #108
2021-04-02 21:56:57 +02:00
philipp 44b53da345 🚚 move @svitejs/vite-plugin-svelte to @sveltejs/vite-plugin-svelte
ref #108
2021-04-02 21:47:43 +02:00
philipp ab45fc144e upgrade vite-plugin-windicss@0.12.1
ref #108
2021-04-02 21:20:48 +02:00
philipp e99e9e0708 update licenses.json
ref #108
2021-04-02 21:20:05 +02:00
philipp 467404bfc8 🐞 fix main.js linking
ref #108
2021-04-02 21:19:49 +02:00
philipp ce50fa2a62 🧹 drop unused dependencies
ref #108
2021-04-02 21:19:29 +02:00
philipp 10a011d842 🐞 fix vite config for production system
ref #108
2021-04-02 21:07:16 +02:00
philipp 5352410d0c 🐞 fix NGINX config
ref #108
2021-04-02 21:06:57 +02:00
philipp c5d155396a 💾 prevent env.js from being cached
ref #108
2021-04-01 19:35:27 +02:00
philipp 93187099d3 🔨 re-added VS Code devcontainer config
ref #108
2021-04-01 19:35:10 +02:00
philipp aa24b1dce5 📃 added readme
ref #108
2021-04-01 19:32:10 +02:00
philipp eb3ede9593 fix dev script
ref #108
2021-04-01 19:30:31 +02:00
philipp d7fecfbd0b version bumps
ref #108
2021-04-01 19:30:15 +02:00
philipp b065b4ff21 📍 version bump + pin
ref #108
2021-03-30 18:36:20 +02:00
niggl 87370d24be Merge branch 'dev' of git.odit.services:lfk/frontend into dev
continuous-integration/drone/push Build is passing
2021-03-30 18:29:03 +02:00
niggl 8f8b9988ad new license file version [CI SKIP] 2021-03-30 16:29:19 +00:00
niggl f8ccf4f5d8 🚀RELEASE v0.11.0 2021-03-30 18:28:53 +02:00
niggl 25d8b86efd Merge pull request 'Generate and print bulk blank cards feature/116-download_blanc_cards' (#117) from feature/116-download_blanc_cards into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #117
2021-03-30 16:27:48 +00:00
philipp 0cd3e937d8 bump vite to 2.1.3
ref #108
2021-03-30 18:21:18 +02:00
niggl 89bb9c215e Sorted translations
ref #116
2021-03-29 18:52:25 +02:00
niggl 2d18686ce7 Bumped lfk client js version
ref #116
2021-03-29 18:52:10 +02:00
niggl 1d999d4910 Now returning cards on creation with pdf
ref #116
2021-03-29 18:23:17 +02:00
niggl 7dfaa7579a Bumped lfk-client-js
ref #116
2021-03-29 18:15:00 +02:00
niggl 08cb079e97 Fixed button styling
ref #116
2021-03-29 17:57:34 +02:00
niggl 450aa83592 Merge branch 'feature/116-download_blanc_cards' of git.odit.services:lfk/frontend into feature/116-download_blanc_cards
# Conflicts:
#	src/components/cards/AddCardBulkModal.svelte
2021-03-29 17:47:18 +02:00
niggl 0614c76e92 Added button (including translations
ref #116
2021-03-29 17:46:56 +02:00
niggl 97e338f9d4 Added button (including translations
ref #116
2021-03-29 17:46:51 +02:00
niggl 636f018daa Added comment
ref #116
2021-03-29 17:44:59 +02:00
niggl c8d639024a Added function for generating cards with pdf
ref #116
2021-03-29 17:44:30 +02:00
philipp 6be2ee626a package cleanup 2021-03-26 21:22:46 +01:00
niggl f7fc1967a5 🚀RELEASE v0.10.0
continuous-integration/drone/push Build is passing
2021-03-26 20:07:14 +01:00
niggl aedb8a765b new license file version [CI SKIP] 2021-03-26 19:06:59 +00:00
niggl cf58bd15c3 Bumped lfk-client version 🔝
continuous-integration/drone/push Build is passing
2021-03-26 20:05:26 +01:00
niggl 34f4f68524 new license file version [CI SKIP] 2021-03-26 19:04:28 +00:00
niggl 09b8144080 Merge pull request 'Implemented password strength test feature/106-password_strength' (#115) from feature/106-password_strength into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #115
2021-03-26 19:03:03 +00:00
niggl f1e6fb4ce7 Merge branch 'dev' into feature/106-password_strength 2021-03-26 19:59:47 +01:00
niggl 2ca63fd1f6 🚀RELEASE v0.9.1
continuous-integration/drone/push Build is passing
2021-03-26 19:59:29 +01:00
niggl a5d25e7d92 Merge pull request 'Org selfservice Link feature/112-org_registration_links' (#114) from feature/112-org_registration_links into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #114
2021-03-26 18:58:34 +00:00
niggl 4167819e7a Formatting🛠
ref #106
2021-03-26 19:52:31 +01:00
niggl 5bd3a463f0 Sorted translations 🌍
ref #106
2021-03-26 19:51:57 +01:00
niggl 79c447b4c6 Added translations
ref #106
2021-03-26 19:51:27 +01:00
niggl 540304f947 User creation can now only be triggered if pw is strong enoug
ref #106
2021-03-26 19:48:42 +01:00
niggl 75d8f7331b Reset can now only be triggered if pw is strong enoug
ref #106
2021-03-26 19:47:26 +01:00
niggl b2509e9e53 Module now exports functions that check if a password is strong enough and equal to a potential confirmation field
ref #106
2021-03-26 19:45:53 +01:00
niggl 7862f44653 Now using pw strength component for user creation
ref #106
2021-03-26 19:31:21 +01:00
niggl 962dd0c1bb Added missing exports
ref #106
2021-03-26 19:29:47 +01:00
niggl 5d5f7c7f5c Now using pw strength component for reset
ref #106
2021-03-26 19:29:37 +01:00
niggl 6aaf838451 Now using pw strength component
ref #106
2021-03-26 19:29:25 +01:00
niggl ad3bd312e9 Added a password strength verification
ref #106
2021-03-26 19:26:26 +01:00
niggl 5fa9939696 Added more cirteria to the password strength component
ref #106
2021-03-26 19:02:09 +01:00
niggl 4956bb0e9c Implemented a custom password strength component
ref #106
2021-03-26 18:47:24 +01:00
niggl c074c12be7 Sorted translations
ref #112
2021-03-26 18:11:49 +01:00
niggl ddbc293e9c Added translations
ref #112
2021-03-26 18:11:23 +01:00
niggl a3921b45c7 Copy now 100% worX
ref #112
2021-03-26 18:11:10 +01:00
niggl 38e1c8c5a1 Merge branch 'feature/112-org_registration_links' of git.odit.services:lfk/frontend into feature/112-org_registration_links 2021-03-26 18:04:08 +01:00
niggl c2d29ff233 Added check if key exists
ref #112
2021-03-26 18:04:05 +01:00
niggl 2316baa898 Added check if key exists 2021-03-26 18:03:58 +01:00
niggl f185d559c0 Formatting
ref #112
2021-03-26 18:01:34 +01:00
niggl 73d95bc004 Fixed changes in wrong file
ref #112
2021-03-26 18:01:17 +01:00
niggl fcd55f89d7 You can now copy the selfservice links to your clipboard
ref #112
2021-03-26 17:59:46 +01:00
niggl f9fe793573 Added checkbox to enable registration
ref #112
2021-03-26 17:37:54 +01:00
niggl bc36411993 Merge branch 'main' into dev
continuous-integration/drone/push Build is passing
2021-03-26 16:17:51 +00:00
niggl 48506236bf Merge branch 'dev' of git.odit.services:lfk/frontend into dev
continuous-integration/drone/push Build is passing
2021-03-26 17:15:51 +01:00
niggl ded9b589fe new license file version [CI SKIP] 2021-03-26 16:16:10 +00:00
niggl 67c3732fad 🚀RELEASE v0.9.0 2021-03-26 17:15:42 +01:00
niggl 2932f4591e Merge pull request 'Runner cards feature/94-runnercard_mgnt' (#111) from feature/94-runnercard_mgnt into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #111
2021-03-26 16:14:45 +00:00
philipp df53c07450 CardsOverview - move to 'enabled' language key
ref #94
2021-03-26 17:13:55 +01:00
philipp 40899e9d80 drop console log - CardDetailModal
ref #94
2021-03-26 17:13:38 +01:00
philipp f794af0950 ✒ typo - "Geb" -> "Gebe"
ref #94
2021-03-26 17:01:40 +01:00
niggl 1665a1a093 Sorted translations 🌍
ref #94
2021-03-26 16:22:10 +01:00
niggl 4a36fb6d95 Added card generation/printing from detail
ref #94
2021-03-26 16:21:46 +01:00
niggl acf78a8822 Added a new runenrcard logo
ref #94
2021-03-26 16:12:40 +01:00
niggl f5c1ec9939 Fixed counting bug
ref #94
2021-03-26 16:05:49 +01:00
niggl 4b3d38b05b Now with working org runenrcard generation
ref #94
2021-03-26 16:05:39 +01:00
niggl 23e0b53107 Added runnercard generation for teams
ref #94
2021-03-26 15:58:39 +01:00
niggl c907486c4d Working runner runnercard generation
ref #94
2021-03-26 15:53:04 +01:00
niggl 6b5945add8 Added translations
ref #94
2021-03-26 15:34:38 +01:00
niggl 55693de934 Removed debug info
ref #94
2021-03-26 15:34:01 +01:00
niggl d467475b6d Basic card generation worX 🎉🎉
ref #94
2021-03-26 15:32:27 +01:00
niggl 44bc14820f Fuggin snowpack bs
ref #94
2021-03-26 14:47:56 +01:00
niggl ec447e2e36 Merge branch 'dev' into feature/94-runnercard_mgnt 2021-03-25 20:30:31 +01:00
niggl 0af2647965 🚀RELEASE v0.8.7
continuous-integration/drone/push Build is passing
2021-03-25 20:30:06 +01:00
niggl 08442154f4 Fixed listen on wrong permission🐞
continuous-integration/drone/push Build is failing
2021-03-25 20:29:33 +01:00
niggl 9f7d2234fb Formatting
ref #94
2021-03-25 20:22:01 +01:00
niggl ddd82a71a7 Moved the pdf generation related componenets to their own folder
ref #94
2021-03-25 20:20:21 +01:00
niggl 014ba3bf67 Teams now use the new sponsoring contracts module
ref #94
2021-03-25 20:17:48 +01:00
niggl c87321f804 Fixed org generation not hiding the generation toast
ref #94
2021-03-25 20:12:32 +01:00
niggl 8b451b3c67 Orgs now use the new sponsoring contracts module
ref #94
2021-03-25 20:09:43 +01:00
niggl 0cfc87fbe6 Moved contract generation to it's own component
ref #94
2021-03-25 20:06:35 +01:00
niggl ae9673070c Now w/ working dialog🎉🎉🎉
ref #94
2021-03-25 19:14:15 +01:00
philipp 008027db0e added windicss settings for VSCode
ref #108
2021-03-25 18:57:33 +01:00
philipp aec5e3473e for await fix - ViteJS
ref #108
2021-03-25 18:56:18 +01:00
philipp 95c8fde72f updated default entrypoint
ref #108
2021-03-25 18:56:02 +01:00
philipp 0f32968fae 🐳 new Dockerfiles
ref #108
2021-03-25 18:55:43 +01:00
philipp ae79e9fea1 basic ViteJS migration
ref #108
2021-03-25 18:55:24 +01:00
niggl 1a52aaf8d1 Moved modal import to overview for simplification
ref #94
2021-03-25 18:55:16 +01:00
niggl d6c315ab8e Sorted translations 🌍
ref #94
2021-03-25 18:39:03 +01:00
niggl 983ce56048 Merge branch 'dev' into feature/94-runnercard_mgnt
# Conflicts:
#	src/locales/de.json
#	src/locales/en.json
2021-03-25 18:38:31 +01:00
niggl de2fe0e9f1 Sorted translations
ref #94
2021-03-25 18:36:51 +01:00
niggl c3c95bf291 🚀RELEASE v0.8.6
continuous-integration/drone/push Build is passing
2021-03-25 18:32:22 +01:00
niggl d2050b5948 Merge pull request 'Know Production Bugs 🐞' (#109) from bugfix/107-prod_issues into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #109
2021-03-25 17:30:27 +00:00
niggl 6b92405bae Removed middlename search from all files that had it
ref #107
2021-03-25 18:19:44 +01:00
niggl 49e87ccb15 Now disabled search by middlename as a quick workaround 🐞
ref #107
2021-03-25 18:16:12 +01:00
niggl 50fffef13b Fixed conflicting css
ref #107
2021-03-25 18:06:28 +01:00
niggl 82b1811971 Sorted translations 👀
ref #107
2021-03-25 18:00:11 +01:00
niggl aeadef60bb Fixed missing translations for scanstations🌍
ref #107
2021-03-25 17:59:50 +01:00
niggl a1ab65a0e9 Sorted translations🌍
ref #107
2021-03-25 17:49:13 +01:00
niggl 17e0805fe6 Errors now toast errors
ref #107
2021-03-25 17:48:54 +01:00
niggl ddd9c396b6 Fixed runner import getting triggered with invalid information
ref #107
2021-03-25 17:46:14 +01:00
niggl ef49e507c1 Fixed outsideclick not clearing import modal🛠
ref #107
2021-03-25 17:34:25 +01:00
niggl fbe74a5d80 Commented out the buggy runner search to prevent bad UX
ref #107
2021-03-25 17:31:53 +01:00
niggl 076893981f Fixed mail login bug🐞📧
ref #107
2021-03-25 17:27:38 +01:00
niggl fac059f02c Now w/working editing
ref #94
2021-03-24 16:58:06 +01:00
niggl 0313f8cc49 Added runnercard detail/edit modal
ref #94
2021-03-24 16:43:05 +01:00
niggl 7ad6b73574 Implemented bulk creation
ref #94
2021-03-23 19:55:55 +01:00
niggl 3cd0468b19 Bumped lfk client lib version
ref #94
2021-03-23 18:57:13 +01:00
niggl f46ccb610e Added bulk creation modal to cards view
ref #94
2021-03-23 18:41:00 +01:00
niggl 8a32569a3b Added bulk card creation modal
ref #94
2021-03-23 18:35:21 +01:00
niggl 535b23ae91 Implemented Add card modal
ref #94
2021-03-23 17:58:13 +01:00
niggl 4715978f81 Added message for missing runner/blanco card)
ref #94
2021-03-23 17:39:14 +01:00
niggl a516aa7775 Formatting
ref #94
2021-03-23 17:34:25 +01:00
niggl 77e9c205f9 Now importing runner overview
ref #94
2021-03-23 17:34:01 +01:00
niggl e852305400 Now routing the cards page
ref #94
2021-03-23 17:31:11 +01:00
niggl c6a15264b3 Added basic card overview
ref #94
2021-03-23 17:29:21 +01:00
niggl 2d0beaaaad Added CardsEmptyState + Emtystate graphic
ref #94
2021-03-23 17:19:10 +01:00
niggl 5c5ef95d2b Added basic cards page
ref #94
2021-03-23 17:13:31 +01:00
niggl e838e6f321 🚀RELEASE v0.8.5
continuous-integration/drone/push Build is passing
2021-03-20 18:47:28 +01:00
niggl ca983c72d4 Merge branch 'dev' of git.odit.services:lfk/frontend into dev 2021-03-20 18:47:08 +01:00
niggl 91dd5256e9 Fixed dupliacate mutation 🐞 2021-03-20 18:47:06 +01:00
philipp 3d4dc2d72b 🚀RELEASE v0.8.4
continuous-integration/drone/push Build is passing
2021-03-20 18:31:46 +01:00
philipp ba3471068a CONFIG: add 'demo' as default username/password 2021-03-20 18:31:31 +01:00
philipp 5a7b2cf886 Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev 2021-03-20 18:27:18 +01:00
philipp cc926e84fb CONFIG: default_username + default_password 2021-03-20 18:27:15 +01:00
niggl fff16e6650 🚀RELEASE v0.8.3
continuous-integration/drone/push Build is passing
2021-03-20 17:51:24 +01:00
niggl d6f6d10cb6 Sorted translation 🌍 2021-03-20 17:50:56 +01:00
niggl 1249904582 More small fixes 2021-03-20 17:50:38 +01:00
niggl 8e0437728b Smaller bugfixes 2021-03-20 17:41:44 +01:00
niggl fb0c0718e4 🚀RELEASE v0.8.2
continuous-integration/drone/push Build is passing
2021-03-20 17:29:35 +01:00
niggl aa8196db3a Now using env base url
continuous-integration/drone/push Build is failing
2021-03-20 17:29:15 +01:00
philipp b2223b5110 🚀RELEASE v0.8.1
continuous-integration/drone/push Build is passing
2021-03-20 17:08:08 +01:00
philipp 3837c5673a Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
continuous-integration/drone/push Build is passing
2021-03-20 17:04:43 +01:00
philipp 910a0860a0 CI - add build:tags pipeline 2021-03-20 17:04:29 +01:00
niggl 009431fb98 🚀RELEASE v0.8.0
continuous-integration/drone/push Build is passing
2021-03-20 16:47:48 +01:00
niggl 579ece6256 new license file version [CI SKIP] 2021-03-20 14:03:04 +00:00
niggl 822e97d3c3 Merge pull request 'User settings feature/103-settings_page' (#104) from feature/103-settings_page into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #104
2021-03-20 14:01:31 +00:00
philipp e0ae2ec42b Settings - rouded corners on password change
ref #103
2021-03-20 15:00:43 +01:00
niggl 859f6e2567 Now also resetting postdata (prevent against password leaks)
ref #103
2021-03-19 19:20:31 +01:00
niggl 120d3c9dc8 Sorted translations🌍
ref #103
2021-03-19 19:19:34 +01:00
niggl 342a95ddbe Now force reloading to log out
ref #103
2021-03-19 19:18:56 +01:00
niggl 0b6134dd80 Added hint to the logout after password update
ref #103
2021-03-19 19:17:16 +01:00
niggl e76854c23b Added translations
ref #103
2021-03-19 19:14:23 +01:00
niggl 24b98983cf Implemented the password change logic
ref #103
2021-03-19 19:14:12 +01:00
niggl 3945f3cf38 Added translations 🌍
ref #103
2021-03-19 19:08:43 +01:00
niggl 5d7eb690e4 Added inputs for password update
ref #103
2021-03-19 19:03:29 +01:00
niggl bef180f4ba Removed useless debug info 🐞
ref #103
2021-03-19 18:53:06 +01:00
niggl e76e5abcf8 Fixed delete_triggered not getting reset
ref #103
2021-03-19 18:50:15 +01:00
niggl 418f9c2662 Added delete Profile button
ref #103
2021-03-19 18:19:05 +01:00
niggl 716b72880a Added deletion confirmation modal
ref #103
2021-03-19 18:12:30 +01:00
niggl 5de0fd792f Its translation time 🌍
ref #103
2021-03-19 18:10:40 +01:00
niggl 13b557aba8 Added new profile deletion modal
ref #103
2021-03-19 18:07:59 +01:00
niggl 34dfc9add6 Added translations🌍
ref #103
2021-03-19 18:02:38 +01:00
niggl 3a4575f251 Implemented profile updates
ref #103
2021-03-19 18:01:09 +01:00
niggl 178c2579d5 Updated old endpoints
ref #103
2021-03-19 17:54:52 +01:00
niggl 50be992b72 Bumped lfk client js version
ref #103
2021-03-19 17:49:48 +01:00
niggl d00f46eee1 Now showing logo as default profile pic
ref #103
2021-03-19 17:48:46 +01:00
niggl 44d6cba403 Added missing translation
ref #103
2021-03-19 17:47:51 +01:00
niggl 37bc5ff17b Implemented change detection
ref #103
2021-03-19 17:31:45 +01:00
niggl e459bb04cc The settings page now boasts your profile picture
ref #103
2021-03-19 17:17:57 +01:00
niggl 01eba88adf Translated headers
ref #103
2021-03-19 16:45:09 +01:00
niggl 016fba5279 Moved settings to their own folder
ref #103
2021-03-19 16:43:39 +01:00
niggl da5d62ae03 🚀RELEASE v0.7.0
continuous-integration/drone/push Build is passing
2021-03-19 16:27:06 +01:00
niggl eb46c5eea6 new license file version [CI SKIP] 2021-03-19 15:26:10 +00:00
niggl 100094e803 Merge pull request 'i18n fixed + dependency bumps bugfix/99-i18n_run' (#102) from bugfix/99-i18n_run into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #102
2021-03-19 15:24:53 +00:00
niggl e723cbf3b3 sorted translations 🌍
ref #99
2021-03-19 15:13:00 +01:00
niggl 00d16ef59f Found a hiddeen missing key👀👀
ref #99
2021-03-19 15:12:38 +01:00
niggl 5204ba5e24 Bumped svelte-related dev dependencies🔥
ref #99
2021-03-18 20:24:21 +01:00
niggl 629aabd3a3 Bumped non-svelte dev dependencies🔝
ref #99
2021-03-18 20:22:07 +01:00
niggl 1b9b9ed372 Bumped router
ref #99
2021-03-18 20:15:46 +01:00
niggl b4e7f9046c Bumped svelte-* dependencies (non-dev)🔝
ref #99
2021-03-18 20:12:30 +01:00
niggl f09224d5c0 Removed lodash as a dependency 🗑
ref #99
2021-03-18 20:10:09 +01:00
niggl 5f6ee33e2b Sorted translations 🌎🌍
ref #99
2021-03-18 20:07:35 +01:00
niggl 635e2ba0e0 Added german translations for the new keys
ref #99
2021-03-18 20:07:06 +01:00
niggl 6109996ade Added missing language keys
ref #99
2021-03-18 20:04:54 +01:00
niggl e4b80c9ab3 Translated missing german stuff 🌍
ref #99
2021-03-18 19:52:54 +01:00
niggl 7521ad8bbb new license file version [CI SKIP] 2021-03-18 17:53:53 +00:00
niggl b994065e18 Merge pull request 'Scan management feature/92-scan_mgnt' (#101) from feature/92-scan_mgnt into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #101
2021-03-18 17:52:30 +00:00
niggl 5b1b84caff Merge branch 'feature/92-scan_mgnt' of git.odit.services:lfk/frontend into feature/92-scan_mgnt 2021-03-18 18:33:06 +01:00
niggl d28a0e1dbb Fix for bug discovered by @philipp
ref #92
2021-03-18 18:33:04 +01:00
niggl 94d52df322 Fix for bug discovered by @philipp
ref #92
2021-03-18 18:32:08 +01:00
niggl 0ae3d36f0c Merge branch 'dev' into feature/92-scan_mgnt 2021-03-18 17:30:57 +01:00
niggl a7fb2b8a1a Merge pull request 'Svelte select dropdown fix bugfix/98-dropdowns' (#100) from bugfix/98-dropdowns into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #100
2021-03-18 16:30:11 +00:00
niggl 16d0dbab5b Sorted translations 🌎
ref #92
2021-03-18 17:28:59 +01:00
niggl 99c3050411 Added translation keys 2021-03-18 17:28:40 +01:00
niggl 937265e828 Added patime to track scan detail
ref #92
2021-03-18 17:28:12 +01:00
niggl 60cd52a959 Merge branch 'bugfix/98-dropdowns' of git.odit.services:lfk/frontend into bugfix/98-dropdowns 2021-03-18 17:24:29 +01:00
niggl b009501a53 Fixed runner group update recognition being weired
ref #98
2021-03-18 17:24:27 +01:00
niggl ee49e78dcd Fixed runner group update recognition being weired
ref #09
2021-03-18 17:24:22 +01:00
niggl 60aa919b14 Added language keys🌎
ref #92
2021-03-18 17:17:15 +01:00
niggl 8252a35771 Reset array
ref #92
2021-03-18 17:10:32 +01:00
niggl fc668c6880 Removed useless console.logs
ref #92
2021-03-18 17:09:44 +01:00
niggl bb7f2a611a Bumped lfk lib version
ref #92
2021-03-18 17:05:32 +01:00
niggl c575c73764 Fixed load order bug
ref #98
2021-03-18 17:02:04 +01:00
niggl bd3ea721c3 Switched import modal over to svelte select
ref #98
2021-03-18 16:24:59 +01:00
niggl 82423ec467 Fixed select bug for org detail 🏠
ref #98
2021-03-18 16:17:21 +01:00
niggl 64311e9652 Fixed select bug for sponsoring detail 🛠
ref #98
2021-03-18 16:08:56 +01:00
niggl 77662b9c19 Fixed select bug for sponsoring modal 🐞
ref #98
2021-03-18 16:04:20 +01:00
niggl b1031e3115 Switched the scanstation detail over to svelte select👀👀
ref #98
2021-03-18 15:56:18 +01:00
niggl 64c96f25d4 Switched the scanstation modal over to svelte select👀👀
ref #98
2021-03-18 15:50:15 +01:00
niggl 5ad42d6ca7 Added select workaround for all things team🏠
ref #98
2021-03-18 15:47:16 +01:00
niggl 0386d4e88a Applied the select fix to all things runner 🏃‍♀️🏃‍♂️
ref #98
2021-03-18 15:35:39 +01:00
niggl cda4512822 Implemented svelt select bug workaround for scan detail🔥🔥🔥
ref #92
2021-03-18 15:17:07 +01:00
niggl eb6af4b4f0 Svelte select is now 100% keyboard useable (or at least in one modal it is....)
ref #92
2021-03-18 14:59:11 +01:00
niggl 4e51b128e6 Fixed visual bug (overflow)
ref #92
2021-03-18 14:41:13 +01:00
niggl 0277263f98 Bumped svelte select version
ref #92
2021-03-18 14:28:29 +01:00
niggl 99fb420d58 Removed depreciated information
ref #92
2021-03-18 14:28:11 +01:00
niggl a45c5da0a7 Fixed broken change detection
ref #92
2021-03-18 13:50:37 +01:00
niggl ff1bc8a44a Fixed bugs with stuff not being displayed🛠
ref #92
2021-03-17 20:02:04 +01:00
niggl 284bdc6e33 Advanced Scan detail
ref #92
2021-03-17 18:21:58 +01:00
niggl 107360cd93 Basic scan detail
ref #92
2021-03-17 17:53:59 +01:00
niggl abf9aa475b Now routing scan detail
ref #92
2021-03-17 17:53:36 +01:00
niggl 6156e04eb3 Merge branch 'dev' into feature/92-scan_mgnt 2021-03-17 17:18:32 +01:00
niggl b541c93797 Merge pull request 'Make dropdowns (selects) searchable feature/91-searchable_dropdowns' (#97) from feature/91-searchable_dropdowns into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #97
2021-03-17 16:05:20 +00:00
niggl 6fd6413d6f Merge branch 'feature/91-searchable_dropdowns' of git.odit.services:lfk/frontend into feature/91-searchable_dropdowns 2021-03-17 17:02:42 +01:00
niggl dfa38d3421 Small bugfixes
ref #91
2021-03-17 17:02:40 +01:00
niggl 6e04b71c1a Small bugfixes
ref #91
2021-03-17 17:01:09 +01:00
niggl 5afa541b30 Added formatted laptime
ref #92
2021-03-17 14:21:02 +01:00
niggl 9e5a093a3a Added new scan icon to add scan modal
ref #92
2021-03-17 14:05:31 +01:00
niggl 2cf8e0291a Added scans to sidebar (including a new icon)
ref #92
2021-03-17 14:04:34 +01:00
niggl 53aa3bc3ae Adjusted filter
ref #92
2021-03-17 14:00:51 +01:00
niggl 1ada5d9c2c Implemented basic scan creation
ref #92
2021-03-17 13:58:31 +01:00
niggl eb0910be57 Added basic scan overview
ref #92
2021-03-17 13:49:51 +01:00
niggl e9d5527482 Fixed emptystate 🛠
ref #92
2021-03-17 13:35:17 +01:00
niggl e6df764562 Fixed typo✏
ref #92
2021-03-17 13:32:35 +01:00
niggl 915bbbbde0 Now routing scans "start" page
ref #92
2021-03-17 13:32:05 +01:00
niggl f67e089ff3 Added basic files for scans
ref #92
2021-03-17 13:29:52 +01:00
niggl b841cc8b95 Reapplied change from dev
ref #91
2021-03-17 11:15:17 +01:00
niggl 5f4b4baadb Merge branch 'dev' into feature/91-searchable_dropdowns
# Conflicts:
#	src/locales/de.json
#	src/locales/en.json
2021-03-17 11:14:38 +01:00
niggl 94b5a54655 Merge branch 'dev' into feature/91-searchable_dropdowns 2021-03-17 11:14:10 +01:00
niggl 95eb8b6ae4 Sorted translations
ref #91
2021-03-17 11:14:04 +01:00
niggl 8acbfa8967 Added translations 🌎
ref #91
2021-03-17 11:13:51 +01:00
niggl 1a115a8423 Small bugfix 🛠
ref #91
2021-03-17 11:09:53 +01:00
niggl 5a2172bb9b Now checking selectables for not being null
ref #91
2021-03-17 11:09:32 +01:00
niggl 6b590671bc Org detail now uses svelte select
ref #91
2021-03-17 11:02:43 +01:00
niggl cee1ab1347 Runner detail now uses svelte select🔥🔥
ref #91
2021-03-17 10:55:25 +01:00
niggl 9d0c6b9ef4 formatting
ref #91
2021-03-17 10:50:26 +01:00
niggl 0e682bf630 Add runner now uses svelte-select 2021-03-17 10:50:13 +01:00
niggl 8b95b300e2 MAde detail editable through the more reacctive process
ref #91
2021-03-17 10:41:24 +01:00
niggl e1bd364278 Formatting 2021-03-17 10:30:27 +01:00
niggl 7edc3427e1 Added contact selection via svelte select
ref #91
2021-03-17 10:29:20 +01:00
niggl d3a3de2eac Fixed initial select value
ref #91
2021-03-17 10:16:22 +01:00
niggl bc2a8caf3e Removed console log 🤫
ref #91
2021-03-17 10:16:02 +01:00
niggl d00446dc7b Merge pull request 'Scan station management feature/93-scan_stations' (#95) from feature/93-scan_stations into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #95
2021-03-15 15:55:28 +00:00
niggl 40ada1c31e Merge branch 'dev' into feature/93-scan_stations
# Conflicts:
#	src/locales/de.json
2021-03-15 16:55:14 +01:00
niggl f24b2b9b4c Applied Docker MTU fix 🛠
continuous-integration/drone/push Build is passing
2021-03-15 16:05:43 +01:00
niggl 2a644d7070 Now using svelte-select
ref #91
2021-03-15 16:05:06 +01:00
niggl ee0c1496e6 Added clear event
ref #91
2021-03-15 16:04:47 +01:00
niggl 1da15783d5 Add Team now uses the new select
ref #91
2021-03-14 20:25:58 +01:00
niggl 6a925cb27f Bugfix for download button dropdown outsideclick
ref #91
2021-03-14 20:25:41 +01:00
niggl 88ad64f113 Added translation strings
ref #91
2021-03-14 19:42:52 +01:00
niggl 1bc840430f Added missing clear
ref #91
2021-03-14 19:42:41 +01:00
niggl 76be8d5a87 New fancy selects for donation details
ref #91
2021-03-14 19:08:56 +01:00
niggl 8c4a54eb07 Added translations for runner searching
ref #91
2021-03-14 17:25:20 +01:00
niggl dab5bee3c0 Added new select for runners
ref #91
2021-03-14 17:25:06 +01:00
niggl bc8548fa1e Merge branch 'dev' into feature/91-searchable_dropdowns 2021-03-14 17:20:46 +01:00
niggl 476f919121 Sorted translations
ref #91
2021-03-14 17:20:35 +01:00
niggl 1c330d0301 Added custom placeholders
ref #91
2021-03-14 17:20:18 +01:00
niggl 47f0cd0b58 Added search languagke keys
ref #91
2021-03-14 17:19:15 +01:00
niggl f97be4e729 Added custom filter/search
ref #91
2021-03-14 17:09:51 +01:00
niggl 48b8dfe973 Now with custom label generation functions
ref #91
2021-03-14 17:04:09 +01:00
niggl 64b6c4d5f7 Merge pull request 'Well that was less work than expected ....' (#96) from feature/90-translations into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #96
2021-03-14 15:31:14 +00:00
niggl fe16c66cf2 New select
ref #91
2021-03-13 14:45:27 +01:00
niggl 8d8695ba13 Well that was less work than expected ....
ref #90
2021-03-13 14:11:55 +01:00
niggl e296256332 Merge branch 'dev' into feature/93-scan_stations 2021-03-12 18:55:32 +01:00
niggl 65111e87c1 Updated ci secrets and type
continuous-integration/drone/push Build is passing
ref odit/org#12
2021-03-12 18:53:49 +01:00
niggl 95b1490f84 Added fancier active states
ref #93
2021-03-12 18:23:53 +01:00
niggl 27a1f57ed3 Added cursor-pointer
ref #93 https://pointerpointer.com/
2021-03-12 18:21:39 +01:00
niggl c6db6c5535 Fixed case sensitivity
ref #93
2021-03-12 18:20:35 +01:00
niggl bd22d3be36 Spelling
#93
2021-03-12 18:17:06 +01:00
niggl ba9d4587cb Switched pipeline type to kubernetes
ref odit/org#12 (comment)
2021-03-10 20:06:39 +01:00
niggl 74c042a86b Sorted translations
ref #93
2021-03-10 20:04:24 +01:00
niggl 95fcd1dcc4 Added german translation 🇩🇪
ref #93
2021-03-10 20:04:07 +01:00
niggl 2de861d4c1 Added "tooltip"
ref #93
2021-03-10 20:03:18 +01:00
niggl e6d80c8ccb Added german translations 🇩🇪
ref #93
2021-03-10 20:01:39 +01:00
niggl 1aa2b3b065 Added new translation keys 🌍
ref #93
2021-03-10 19:57:36 +01:00
niggl 88566719ec Added station token copy modal
ref #93
2021-03-10 19:55:32 +01:00
niggl 870e772da2 Fixed emptystate svg
ref #93
2021-03-10 18:13:20 +01:00
niggl e8e3ddceff Added icon 🖼
ref #93
2021-03-10 18:12:04 +01:00
niggl a5d1b76891 Sorted translations 👀
ref #93
2021-03-10 18:06:23 +01:00
niggl e93f4e99f9 Added german translations
ref #93
2021-03-10 18:05:17 +01:00
niggl 50aa891709 i18n run: Added keys 🌍
ref #93
2021-03-10 18:01:09 +01:00
niggl 4b47e70b13 Added scanstations to sidebar
ref #93
2021-03-10 17:53:19 +01:00
niggl c4acf774ec You can now delete a station from it's detail
ref #93
2021-03-10 17:46:19 +01:00
niggl 7ff1d50079 Spelling+Formatting
ref #93
2021-03-10 17:43:59 +01:00
niggl 258b3cea66 Added scanstation detail
ref #93
2021-03-10 17:43:32 +01:00
niggl a3daa2d24f Now routing scan station detail
ref #93
2021-03-10 17:38:56 +01:00
niggl 9f754ef0e9 Added station deletion confirmation dialog
ref #93
2021-03-10 17:24:51 +01:00
niggl 773fbfc579 Changed row order
ref #93
2021-03-10 17:18:45 +01:00
niggl 85fa9d942e Finished scanstations base view
ref #93
2021-03-10 17:16:50 +01:00
niggl 83e782c7c5 Finished scanstationmodal (without i18n)
ref #93
2021-03-10 17:16:14 +01:00
niggl 9ee768551f Basic scanstation creation
ref #93
2021-03-10 17:10:51 +01:00
niggl e45f8fa9ef You can now add scanstations
ref #93
2021-03-10 17:06:22 +01:00
niggl 891ea2da12 Fixed routing
ref #93
2021-03-10 17:05:59 +01:00
niggl 5e417f0714 Fixed nameing
ref #93
2021-03-10 16:52:08 +01:00
niggl c53b579fca Added basic table for scanstations
ref #93
2021-03-10 16:51:57 +01:00
niggl ca9c390bb2 Now routing scan statins overview
ref #93
2021-03-10 16:41:29 +01:00
niggl 7d654f4a20 new license file version [CI SKIP] 2021-03-01 16:46:03 +00:00
niggl b810bb01db Merge pull request 'Spnonsoring contract language selector feature/84-sponsoringcontract_language_selector' (#89) from feature/84-sponsoringcontract_language_selector into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #89
2021-03-01 16:45:05 +00:00
niggl c2bd696bfe Implemented rough outside click handler for the dropdown
ref #84
2021-02-28 17:39:21 +01:00
niggl 9fec315910 Clicking on a dropdown option now closes it everywhere
ref #84 #89
2021-02-28 17:17:41 +01:00
niggl 9a8a978e49 Removed locale overrides
ref #84
2021-02-28 16:34:04 +01:00
niggl e24b84e709 New download buttons for everyone (that can generate sponsoring contracts)
ref #84
2021-02-28 16:33:17 +01:00
niggl 305b18ef57 Switched the icon style
ref #84
2021-02-28 16:26:54 +01:00
niggl 22e9f53c42 Moved pdf generation to function instead of onclick for all components
ref #48
2021-02-27 20:09:50 +01:00
niggl 6870e31a81 Sorted translations
ref #48
2021-02-27 19:34:16 +01:00
niggl e07d1e42e2 And with working i18n 🌍
ref #48
2021-02-27 19:33:57 +01:00
niggl c89caf7855 Now with dropdown aiutoclose
ref #48
2021-02-27 19:32:21 +01:00
niggl 3b7c25b106 Working button onklicks
ref #48
2021-02-27 19:30:56 +01:00
niggl 6079e1fa90 Basic sponsoring language dropdown for runners
ref #84
2021-02-27 19:26:47 +01:00
niggl 434466b306 Merge pull request 'Usergroup management in the UI feature/48-usergroup-management' (#88) from feature/48-usergroup-management into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #88
2021-02-26 19:07:17 +00:00
niggl e1ac35f848 Fixed root breadcrumb linking
ref #48
2021-02-26 20:01:16 +01:00
niggl 5994b22464 User permission update reactivity fix
ref #48
2021-02-26 19:59:38 +01:00
niggl bfc93158f5 Udergroup permission reactivity fix
ref #48
2021-02-26 19:58:46 +01:00
niggl 29f99f0b20 Added missing translations 🌍
ref #48
2021-02-26 19:53:18 +01:00
niggl e4872131c8 Sorted translations
ref #48
2021-02-26 19:26:47 +01:00
niggl 16e1434f2a Changed group icon
ref #48
2021-02-26 19:25:47 +01:00
niggl 842badfa69 Merge branch 'feature/48-usergroup-management' of git.odit.services:lfk/frontend into feature/48-usergroup-management 2021-02-26 19:25:06 +01:00
niggl 8ebc88aebb Updated users icon
ref #48
2021-02-26 19:25:04 +01:00
niggl c111ec9d91 Updated users icon
ref #48
2021-02-26 19:22:30 +01:00
niggl e85cdaf324 More i18n 🌍
ref #48
2021-02-26 19:10:10 +01:00
niggl 599d340a72 Added missing translations 🌍
ref #48
2021-02-26 19:01:23 +01:00
niggl 89b7fb8072 Added missing translations 🌍
ref #48
2021-02-26 18:59:48 +01:00
niggl dcaca2ecbd Translated stuff 🌍
ref #48
2021-02-26 18:56:08 +01:00
niggl b8725c96cd Formatting
ref #48
2021-02-26 18:55:31 +01:00
niggl 36930259d2 Added translation keyz
ref #48
2021-02-26 18:49:09 +01:00
niggl 4397566f1e Fixed Back linking
ref #48
2021-02-26 18:48:57 +01:00
niggl 7c324869a4 Working suergroup permissions overview
ref #48
2021-02-26 18:23:02 +01:00
niggl 7e80608066 Fix for user permission availdable
ref #48
2021-02-26 18:22:15 +01:00
niggl af7e44cf7c Now routing to gorup permissions
(to be implemented) ref #48
2021-02-26 18:01:26 +01:00
niggl 05099d066b Added permissions list to usergroup detail
ref #48
2021-02-26 17:58:57 +01:00
niggl 937486a66b Added group detail routing
ref #48
2021-02-25 20:56:22 +01:00
niggl e8de1f6d9c New image for emptystate
ref #48
2021-02-25 20:48:21 +01:00
niggl cd9a5469fd Formatting
ref #48
2021-02-25 20:45:37 +01:00
niggl 1124f25ea3 Renamed button
ref #48
2021-02-25 20:28:45 +01:00
niggl a79a87de4c Formatting
ref #48
2021-02-25 20:27:46 +01:00
niggl d2193bf428 Finished group creation modal
ref #48
2021-02-25 20:27:03 +01:00
niggl d9eab9f254 Added groupoverview to router
ref #48
2021-02-25 20:13:30 +01:00
niggl 7d08ea8466 Renamed folder
ref #48
2021-02-25 20:13:17 +01:00
niggl ba1eb2fa73 Merge branch 'dev' into feature/48-usergroup-management
# Conflicts:
#	src/components/dashboard/Dashboard.svelte
2021-02-25 20:09:44 +01:00
niggl 4dbca6096f New folder structure
ref #48
2021-02-25 20:08:32 +01:00
niggl 03be2d0492 Merge pull request 'Donation management feature/79-donation_management' (#87) from feature/79-donation_management into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #87
2021-02-25 16:35:10 +00:00
niggl b0aca9de13 Added the new, shiny badges to donor overview
ref #79
2021-02-25 17:34:11 +01:00
philipp 019a0297a9 DonorDetail accessibility improvements 👀
ref #79
2021-02-25 17:31:26 +01:00
niggl 0f93febd86 Ordered locales
ref #79
2021-02-25 17:13:22 +01:00
niggl d6c96b781f Fixed missing middlename action
ref #79
2021-02-25 17:13:03 +01:00
niggl 918bb94644 Added missing translation
ref #79
2021-02-25 17:11:53 +01:00
niggl a8774fa524 Fixed missing inversion
ref #79
2021-02-25 17:10:25 +01:00
niggl e4b908ecde Merge branch 'feature/79-donation_management' of git.odit.services:lfk/frontend into feature/79-donation_management
# Conflicts:
#	src/components/donors/DonorDetail.svelte
2021-02-25 17:08:23 +01:00
niggl 247ba40309 Updated donor badege styleing
ref #79
2021-02-25 17:08:13 +01:00
niggl fcf01ba677 Updated donor badege styleing
ref #79
2021-02-25 17:07:06 +01:00
niggl fb5a64c251 Fixed donation badges now show their amount
ref #79
2021-02-25 16:58:14 +01:00
niggl 3d51ba0dc2 Fixed text size mismatch
ref #79
2021-02-25 16:55:19 +01:00
niggl 07636f51c4 Removed useless style
ref #79
2021-02-25 16:53:04 +01:00
niggl eff2050959 Sorted translations
ref #79
2021-02-25 16:08:11 +01:00
niggl c96a21cf99 Added missing translation keys
ref #79
2021-02-25 16:07:48 +01:00
niggl d4d847059a Added german translations
ref #79
2021-02-25 15:58:21 +01:00
niggl 880d722912 Added translation keys
ref #79
2021-02-25 15:55:12 +01:00
niggl 1ef1053d3f Added custom i18n ally insert format
ref #79
2021-02-25 15:45:11 +01:00
niggl fa522a85d6 Added new icon for donations
ref #79
2021-02-25 15:40:34 +01:00
niggl f09e58c69c Formatting
ref #79
2021-02-25 15:05:27 +01:00
niggl 63e02492e8 Now the saveing button even worx :O
ref #79
2021-02-25 15:04:19 +01:00
niggl fd406eb3e6 Now routing stuff to the donation detail
ref #79
2021-02-25 14:58:03 +01:00
niggl 88ade26ef7 Added basic donation detail
ref #79
2021-02-25 14:57:45 +01:00
niggl 3aea259e41 Donors now get their donations linked in the donor detail
ref #79
2021-02-25 14:09:34 +01:00
niggl 0f64767437 Donors now get their donations linked in the donor overview
ref #79
2021-02-25 14:06:41 +01:00
niggl d2430badbe Amount now also self-resetts
ref #79
2021-02-24 20:56:32 +01:00
niggl a880ed2b18 Adjusted togle label font size
ref #79
2021-02-24 20:55:42 +01:00
niggl e0f0fa9a2a Merge branch 'dev' into feature/79-donation_management 2021-02-24 20:50:02 +01:00
niggl 5d2025aa43 Working add fixed/normal switch
ref #79
2021-02-24 20:49:43 +01:00
niggl 8b7f5a765b Merge pull request 'i18n fix run no.1 feature/69-i18n_fixes' (#85) from feature/69-i18n_fixes into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #85
2021-02-24 19:49:13 +00:00
niggl 9cd94004fc Merge pull request 'Fixed refresh page reload bug' (#86) from feature/82-auth_refresh_bug into dev
continuous-integration/drone/push Build is failing
Reviewed-on: #86
2021-02-24 19:49:00 +00:00
niggl 8042bca7cc Enabled add modal
ref #79
2021-02-24 20:28:02 +01:00
niggl 8d89d158d1 Added basic donation overview
ref #79
2021-02-24 19:44:57 +01:00
niggl ccacdf274b Added donation route
ref #79
2021-02-24 19:44:45 +01:00
niggl f1ceef05fc Added basic overview with emptystate
ref #79
2021-02-24 19:25:31 +01:00
niggl c5697242ee Fixed refresh page reload bug
ref #82
2021-02-24 19:17:18 +01:00
niggl d0a48ab94b More missing translations 🌍
ref #69
2021-02-24 18:46:09 +01:00
niggl 2b037d41ac Added missing translations
ref #69
2021-02-24 18:39:45 +01:00
niggl b7d38dd849 Now using translations in org/add/address
ref #69
2021-02-24 17:13:16 +01:00
niggl 02d24139e9 Fixed known translation mishaps
ref #69
2021-02-24 16:58:30 +01:00
niggl ad638e8bc8 Merge pull request 'Donor management feature/78-donor_mgnt' (#80) from feature/78-donor_mgnt into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #80
2021-02-24 15:53:50 +00:00
niggl 76cb20debe Merge branch 'feature/78-donor_mgnt' of git.odit.services:lfk/frontend into feature/78-donor_mgnt 2021-02-24 16:51:25 +01:00
niggl 3e9383e6d9 Formatting
ref #78
2021-02-24 16:51:19 +01:00
philipp aec8bf56a2 🖼 new donor empty image
ref #78
2021-02-24 16:44:41 +01:00
niggl 18335e3325 Normalized svg
ref #78
2021-02-24 16:36:20 +01:00
niggl bca9605d4a Fixed missing icon
ref #78
2021-02-24 16:35:41 +01:00
niggl 0321f0e979 Updated icons
ref #78
2021-02-24 16:23:21 +01:00
niggl f97c2a36f6 Fixed deletion in detail bug
ref #78 #80
2021-02-24 16:14:10 +01:00
niggl 5d945f5bc5 Added total dontaion amount to donor detail
ref #78
2021-02-20 19:55:11 +01:00
niggl 1c4975589f Implemented currency formatting
ref #78
2021-02-20 19:49:53 +01:00
niggl fffe5c2c4b Updated donot empty logo
ref #78
2021-02-20 19:45:14 +01:00
niggl 3a57e1c766 Updated sponsoring logo
ref #78
2021-02-20 19:33:06 +01:00
niggl 8b70882fec Sorted translations
ref #78
2021-02-20 19:27:20 +01:00
niggl 7fb7ba0d2b i18n translation spree 🌍
ref #78
2021-02-20 19:27:04 +01:00
niggl 78514c6572 Implemented receipt needed
ref #78
2021-02-20 19:19:44 +01:00
niggl 19393006ef i18n run
ref #78
2021-02-20 19:13:33 +01:00
niggl cb704c4551 Added donor detail
ref #78
2021-02-20 19:04:08 +01:00
niggl 04a09c3ce5 Converted total donation amount to €
ref #78
2021-02-20 18:51:49 +01:00
niggl ca8f978667 Some i18n 🌍
ref #78
2021-02-20 18:49:05 +01:00
niggl 0cc91ac037 Added donors to sidebar
ref #78
2021-02-20 18:44:29 +01:00
niggl 1b6f86669c Implemented donor creation modal
ref #78
2021-02-20 18:40:41 +01:00
niggl 264868bb6a Implmented donor deletion confirmation
ref #78
2021-02-20 18:31:02 +01:00
niggl 02087a541e Implemented donor overview and deletion
ref #78
2021-02-20 18:26:18 +01:00
philipp dee0e37a85 Merge pull request 'feature/62-contract-generation' (#76) from feature/62-contract-generation into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #76
close #62
2021-02-20 16:36:47 +00:00
niggl ea7a4a560b Merge branch 'dev' into feature/62-contract-generation 2021-02-20 16:35:31 +00:00
niggl f63e17775c Fixed typo
ref #62
2021-02-20 17:35:05 +01:00
niggl c4240d36f7 Merge branch 'feature/62-contract-generation' of git.odit.services:lfk/frontend into feature/62-contract-generation 2021-02-20 17:34:37 +01:00
niggl ed13a0d14b Now the toast hides the generation toast
ref #62
2021-02-20 17:34:35 +01:00
niggl 8fa0be7633 Now the toast hides the generation toast
ref #62
2021-02-20 17:32:49 +01:00
niggl a99c022608 Added missing translations 🌍
ref #62
2021-02-20 17:28:31 +01:00
niggl 12bcbd28f3 Error message on pdf generation fail
ref #62
2021-02-20 17:25:48 +01:00
philipp 4ece21cdf2 progress toast in RunnersOverview
ref #62
2021-02-20 17:21:45 +01:00
philipp a7642c2da4 basic progress toasts
ref #62
2021-02-20 17:19:17 +01:00
niggl 32024cf2c5 Merge pull request 'Mitigated null error' (#77) from feature/64-dialog_clearing_bug into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #77
2021-02-20 16:03:45 +00:00
niggl ef373caba7 Merge branch 'dev' into feature/64-dialog_clearing_bug 2021-02-20 15:59:25 +00:00
niggl 396bd22199 Mitigated null error
ref #64
2021-02-20 16:58:51 +01:00
philipp 4bff50a088 Merge pull request 'Small bugfixes - feature/64-dialog_clearing_bug' (#75) from feature/64-dialog_clearing_bug into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #75
close #64
2021-02-20 15:54:52 +00:00
philipp dbc0ab76af PDF download from TeamDetail + TeamsOverview
ref #62
2021-02-20 16:53:30 +01:00
philipp 289a8c14d3 ✒ change "Edit" table actions to "Detail"
ref #62
2021-02-20 16:47:04 +01:00
niggl 44ed633cbf Fixed orgs/teams not being marked as selected on initial modal opening
ref #64
2021-02-20 16:46:55 +01:00
philipp 0a55d73146 PDF generation from OrgDetail
ref #62
2021-02-20 16:46:12 +01:00
philipp 40dda1150c OrgOverview - multiple pdf download
ref #62
2021-02-20 16:42:06 +01:00
niggl 09b61ec684 Merge branch 'feature/64-dialog_clearing_bug' of git.odit.services:lfk/frontend into feature/64-dialog_clearing_bug 2021-02-20 16:31:39 +01:00
niggl e53467da22 Fixed clear on import bug
ref #64
2021-02-20 16:31:37 +01:00
niggl 09d27c0b05 Fixed clear on import bug
ref #54
2021-02-20 16:31:30 +01:00
philipp 3b18be5874 PDF from RunnerDetail
ref #62
2021-02-20 16:17:20 +01:00
philipp ff15308c03 🌎 i18n
ref #62
2021-02-19 20:06:59 +01:00
philipp fa3dc870d3 📃 pdf generation in RunnersOverview
ref #62
2021-02-19 20:02:01 +01:00
philipp 5e6ada140c reactive button for checkboxes in table
ref #62
2021-02-19 19:24:36 +01:00
philipp e8f7c1c832 basic select boxes in table
ref #62
2021-02-19 19:21:08 +01:00
philipp 266a11f64f Merge commit 'b337873ca214682487844973104772539956c09a' into feature/48-usergroup-management
ref #48
2021-02-19 18:51:07 +01:00
philipp e442b92a5f Merge commit '6d0bca6d6783d3f7bbff5d413b158c6b60720bd8' into feature/48-usergroup-management
ref #48
2021-02-19 18:49:33 +01:00
niggl b337873ca2 Merge branch 'dev' of git.odit.services:lfk/frontend into dev
continuous-integration/drone/push Build is passing
2021-02-19 18:49:12 +01:00
niggl 896fff04aa Fixed non-automatic logout
closes #38
2021-02-19 18:49:07 +01:00
philipp 6d0bca6d67 Merge pull request 'feature/69-translation-keys' (#74) from feature/69-translation-keys into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #74
close #69 . nice.
2021-02-19 17:27:43 +00:00
niggl d53c1ae2bd Merge branch 'dev' into feature/69-translation-keys
# Conflicts:
#	src/components/orgs/OrgDetail.svelte
#	src/components/runners/RunnersOverview.svelte
2021-02-19 18:23:38 +01:00
niggl afd73d53be new license file version [CI SKIP] 2021-02-19 17:05:04 +00:00
niggl 652e55e80e Merge pull request 'Addresses for orgs and a bunch of bugfixes feature/72-adddress_for_everyone' (#73) from feature/72-adddress_for_everyone into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #73
2021-02-19 17:04:18 +00:00
philipp 9aa8e7edff Merge pull request 'first merge to main 🚀' (#71) from dev into main
Reviewed-on: #71
Reviewed-by: Nicolai Ort <info@nicolai-ort.com>
2021-02-19 17:03:02 +00:00
philipp d67dfdf2e7 🐞 fixed translation keys
ref #69
2021-02-19 18:00:00 +01:00
philipp 51f2d96ad6 Merge branch 'feature/69-translation-keys' of https://git.odit.services/lfk/frontend into feature/69-translation-keys
# Conflicts:
#	src/locales/de.json
#	src/locales/en.json
2021-02-19 17:57:10 +01:00
philipp 30867b4ba1 🐞 fixed bug in Tracks datatable translation keys
ref #69
2021-02-19 17:54:52 +01:00
niggl ec8d946a41 Implemented detail address add fix
ref #72
2021-02-19 17:43:36 +01:00
niggl 1eea935207 🐞 fixed address removal bug ContactDetail
ref #72
2021-02-19 17:28:26 +01:00
philipp 616990b930 🐞 fixed bug in OrgDetail address reactivity
ref #72
2021-02-19 17:24:22 +01:00
niggl e5c31c9dd4 First part of org detail address edit
ref #72
2021-02-19 16:36:17 +01:00
niggl 4f3f7d1edb Fixed wrong relation getting targeted
ref #72
2021-02-19 16:31:17 +01:00
niggl 86f13003b5 Implemented org address creation modal logic
ref #72
2021-02-19 16:08:34 +01:00
niggl 6d2431b683 Added address to org creation dialog (styleing only)
ref #72
2021-02-19 16:07:12 +01:00
niggl 57e17f2864 Runner Contact information column npow features address
ref #72
2021-02-19 15:51:15 +01:00
niggl bcc7d7770e Added address to org overview
ref #72
2021-02-19 15:47:23 +01:00
niggl 89ea40d7f3 Merge branch 'feature/69-translation-keys' of git.odit.services:lfk/frontend into feature/69-translation-keys
# Conflicts:
#	src/components/orgs/OrgOverview.svelte
2021-02-19 15:36:23 +01:00
niggl 56b5008278 Replaced untranslated key with already existant key
ref #69
2021-02-19 15:36:12 +01:00
niggl 555778fca4 Replaced untranslated key with already existant key
ref #69
2021-02-19 15:35:29 +01:00
niggl ec1a6226a9 Unified key translation style
ref #69
2021-02-19 15:32:40 +01:00
niggl 3c541ada89 Genered soem runner related keys
ref #69
2021-02-19 15:29:35 +01:00
niggl 5f677e71e9 Merge branch 'dev' into feature/69-translation-keys 2021-02-19 15:22:12 +01:00
niggl 5b3e66c4f6 Removed key duplicate from last merge
ref #69
2021-02-19 14:55:16 +01:00
philipp 9b0252fb75 some more translation keys
ref #69
2021-02-18 18:36:04 +01:00
niggl 2e3750c87c Translated all missing translations 🌍
ref# 69
2021-02-18 18:30:48 +01:00
philipp 377d691053 🇩🇪 more german translations
ref #69
2021-02-18 18:18:06 +01:00
philipp e90fe73aa2 drop filepond keys
ref #69
2021-02-18 18:12:16 +01:00
philipp 3baa681c2b Merge branch 'feature/69-translation-keys' of https://git.odit.services/lfk/frontend into feature/69-translation-keys 2021-02-18 18:11:06 +01:00
philipp a588bc4631 translation keys
ref #69
2021-02-18 18:09:57 +01:00
niggl b195c707b0 Fixed privacy/imprint fallback bug
ref #69
2021-02-18 17:49:26 +01:00
niggl 25ac84e5fd Formatting
ref #69
2021-02-18 17:45:27 +01:00
niggl 5e9df32bfa Merge branch 'feature/69-translation-keys' of git.odit.services:lfk/frontend into feature/69-translation-keys 2021-02-18 17:37:09 +01:00
niggl 722feac8bd Removed unused locales
ref #69
2021-02-18 17:37:07 +01:00
niggl 4be87a64b9 Removed unused locales
ref #69
2021-02-18 17:35:46 +01:00
philipp 505ca6a58e ForgotPassword demo for translation with interpolation
ref #69
2021-02-18 17:24:53 +01:00
philipp 5f1c8f3627 Merge commit '9faa93e29239182871b82bca211531fb95d37b7f' into feature/69-translation-keys
ref #69
2021-02-18 17:19:50 +01:00
niggl 3834079481 new license file version [CI SKIP] 2021-02-18 16:17:27 +00:00
niggl 9faa93e292 Merge pull request 'component/ structure cleanup feature/68-component-cleanup' (#70) from feature/68-component-cleanup into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #70
2021-02-18 16:16:43 +00:00
niggl 27609dc5e0 Removed debug output
ref #68
2021-02-18 17:13:58 +01:00
niggl 2b57d49e4e Dependency bump 👊
ref #68
2021-02-18 17:13:19 +01:00
niggl dc0c738471 Added license to package
ref #68
2021-02-18 17:08:19 +01:00
niggl ca41f4d4f2 Removed filepond
ref #68
2021-02-18 17:06:54 +01:00
niggl e1427f3ecb renamed folder and removed useless files
ref #68
2021-02-18 17:06:25 +01:00
niggl e2fb9a66ad Reimported simple.css
ref #68
2021-02-18 17:04:39 +01:00
niggl 7278648642 Removed usless console logs
ref #68
2021-02-18 17:03:05 +01:00
niggl a4c955ce85 Fixed org deletion dialog 2021-02-18 17:01:08 +01:00
niggl f086027910 Fixed store destrucuured import
ref #68
2021-02-18 16:57:05 +01:00
niggl 543b3bd937 Fixed store not being found
ref #68
2021-02-18 16:56:49 +01:00
niggl c0534a3b06 Initial component sort/cleanup
ref #68
2021-02-18 16:51:15 +01:00
philipp 0c9785af36 new license file version [CI SKIP] 2021-02-18 15:14:23 +00:00
philipp 482149139a Merge pull request 'feature/50-contact-management' (#67) from feature/50-contact-management into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #67
close #50
2021-02-18 15:13:34 +00:00
philipp c89038f337 Merge branch 'dev' into feature/50-contact-management
ref #50
2021-02-18 16:11:49 +01:00
niggl 696d3ffabf Fixed contact update detection bug
ref #50
2021-02-18 16:05:20 +01:00
niggl 14e5d0e740 Fixed address update bug
ref #50
2021-02-18 15:45:38 +01:00
niggl e4ae1dd475 Fixed group posting issue
ref #50
2021-02-17 20:23:30 +01:00
niggl 46cd262fab Fixed modal multiselect
ref #50
2021-02-17 20:15:11 +01:00
philipp 3f5418083f Merge pull request 'Translated everything feature/65-translations' (#66) from feature/65-translations into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #66
2021-02-17 18:52:14 +00:00
philipp 1586c2f9e6 OrgDetail - edit contact
ref #50
2021-02-17 19:51:04 +01:00
niggl e64b318a42 Sorted locales
ref #65
2021-02-17 19:46:13 +01:00
philipp 2033572c83 TeamDetail - edit contact
ref #50
2021-02-17 19:45:37 +01:00
niggl ce678c1b76 Gendered some stuff
ref #65
2021-02-17 19:45:25 +01:00
niggl 83495b101c German spell check
ref #65
2021-02-17 19:43:16 +01:00
niggl 6c2a5f904d Now w/ 100% german translation 🌍
ref #65
2021-02-17 19:39:19 +01:00
philipp c1251d3332 🌎 Contacts i18n
ref #50
2021-02-17 19:15:05 +01:00
philipp 4ef1b7abe8 🎉 ContactDetail + ContactOverview
ref #50
2021-02-17 19:02:35 +01:00
niggl d822e4ab3f Fixed import modal width
continuous-integration/drone/push Build is passing
2021-02-16 17:25:57 +01:00
philipp b01fe050d2 🔗 link to ContactDetail from TeamsOverview
ref #50
2021-02-15 20:54:09 +01:00
philipp 1a4cf211eb 🔗 link to ContactDetail from OrgOverview
ref #50
2021-02-15 20:53:23 +01:00
philipp 4541304fa8 🚧 WIP on ContactDetail
ref #50
2021-02-15 20:50:15 +01:00
philipp 894160f3f7 ContactDetail - added checkbox for optional address
ref #50
2021-02-15 18:19:25 +01:00
philipp 6a91bd53e2 🐞 fixed null addresses in ContactsOverview
ref #50
2021-02-15 17:52:20 +01:00
philipp 0f013304ef 🧹 ContactOverview refinement
ref #50
2021-02-15 17:46:01 +01:00
philipp 6f4f4ccb16 ContactDetail route
ref #50
2021-02-15 17:45:41 +01:00
philipp 7138ca1f5f AddContactModal - allow optional address
ref #50
2021-02-15 17:45:20 +01:00
philipp 45e7f6a0d1 🎉 working AddContactModal
ref #50
2021-02-13 20:30:38 +01:00
philipp a7098df9cf ContactsEmptyState
ref #50
2021-02-13 20:13:05 +01:00
philipp 054c7faaac basic Contact components
ref #50
2021-02-13 19:26:38 +01:00
philipp c3a4c659c0 Merge branch 'dev' into feature/48-usergroup-management 2021-02-13 15:39:14 +01:00
philipp 087c85e586 🚀RELEASE v0.6.0
continuous-integration/drone/push Build is passing
2021-02-12 19:18:33 +01:00
philipp 43df188df1 new license file version [CI SKIP] 2021-02-12 18:16:52 +00:00
philipp 1d40c6d068 Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
continuous-integration/drone/push Build is passing
2021-02-12 19:15:41 +01:00
philipp 6614242df6 dependency bump 2021-02-12 19:15:34 +01:00
philipp b25dc623cf new license file version [CI SKIP] 2021-02-12 18:10:08 +00:00
philipp 9d3bb4e4e3 Merge pull request 'feature/52-runner-filters' (#63) from feature/52-runner-filters into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #63
close #52
2021-02-12 18:09:21 +00:00
philipp 5dc11c285d RunnersOverview - support should_display_based_on_id search
ref #52
2021-02-12 19:06:31 +01:00
philipp 575b4ce970 RunnersOverview - basic working filter
ref #52
2021-02-12 18:47:46 +01:00
philipp e23821a7cb WIP on filter
ref #52
2021-02-12 18:04:10 +01:00
philipp e415258787 basic select filtering in RunnersOverview
ref #52
2021-02-09 19:22:20 +01:00
philipp eddfeb10a5 UserGroupsEmptyState, UserGroupsOverview, basic GroupDetail
ref #48
2021-02-09 17:37:38 +01:00
philipp 0361f8ad69 basic UserGroup components
ref #48
2021-02-09 16:31:37 +01:00
philipp 1451991d03 Merge pull request 'feature/43-password-reset' (#61) from feature/43-password-reset into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #61
close #43
2021-02-07 16:11:16 +00:00
philipp 92fee08dc4 ⏮decode base64 reset key 2021-02-07 13:26:57 +01:00
philipp 7b7e484091 🧹 formatting 2021-02-07 13:25:39 +01:00
philipp e7291a31f3 Merge pull request 'feature/51-teamoverview-badge-org' (#59) from feature/51-teamoverview-badge-org into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #59
close #51
2021-02-07 12:12:57 +00:00
philipp 2dc31912cc Merge pull request 'feature/47-sidebar-responsiveness' (#60) from feature/47-sidebar-responsiveness into dev
continuous-integration/drone/push Build is failing
Reviewed-on: #60
close #47
2021-02-07 12:12:29 +00:00
philipp 428a8a10ff 🌍 i18n for ResetPassword
ref #43
2021-02-07 13:11:08 +01:00
philipp 8b2f1965e2 👀 ResetPassword - success and error states
ref #43
2021-02-07 13:08:44 +01:00
philipp b18a99e4df added basic UI for ResetPassword
ref #43
2021-02-07 12:51:21 +01:00
philipp 1fac0c8640 😬 use actual team id for RunnersOverview badge
ref #51
2021-02-07 12:18:34 +01:00
philipp f0be73c2cd Merge commit '65f49489ad2e0cff30560e4c326ca7294d7f6190' into feature/51-teamoverview-badge-org 2021-02-07 12:11:09 +01:00
philipp 42bd632539 👀 only display navbar on sm devices / hide on md and up 2021-02-07 12:07:25 +01:00
philipp f8014c6213 🐞 re-add sidebar component 2021-02-07 12:06:54 +01:00
philipp 65f49489ad new license file version [CI SKIP] 2021-02-07 11:05:54 +00:00
philipp e9e24d5f2d Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
continuous-integration/drone/push Build is passing
2021-02-07 12:05:08 +01:00
philipp 369b09972c general dependency bump 2021-02-07 12:04:55 +01:00
philipp e4e2bdac72 new license file version [CI SKIP] 2021-01-30 16:58:42 +00:00
philipp ec0db39184 Merge pull request 'feature/15-runner-import' (#58) from feature/15-runner-import into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #58
close #15
2021-01-30 16:57:59 +00:00
philipp a02be78df5 RunnersOverview badge to team/org
ref #51
2021-01-30 17:56:58 +01:00
philipp 3490abe9a7 Org badge in TeamsOverview
ref #51
2021-01-30 17:56:40 +01:00
philipp b5013426e6 reactivity in import table
ref #15
2021-01-30 17:50:16 +01:00
philipp 7dd0881d29 working import binding
ref #15
2021-01-30 17:45:12 +01:00
philipp acf0562851 ImportRunnerModal - differenciate between team and org import
ref #15
2021-01-30 17:27:51 +01:00
philipp 80c3a90d6f client library bump
ref #15
2021-01-30 17:14:20 +01:00
philipp c6985087a8 layout for Import from RunnerOverview
ref #15
2021-01-30 17:05:19 +01:00
philipp ef50e2d5ce Merge pull request 'feature/56-footer-version-loading' (#57) from feature/56-footer-version-loading into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #57
close #56
2021-01-30 15:33:24 +00:00
niggl ed1dc6e8d5 Merge branch 'dev' into feature/56-footer-version-loading 2021-01-30 15:28:07 +00:00
philipp c2d7a319a0 use onMount event instead of DOMready
ref #56
2021-01-30 16:24:48 +01:00
philipp 0e04298b7c new license file version [CI SKIP] 2021-01-30 15:17:37 +00:00
philipp 3a5a73b02c Merge pull request 'feature/46-imprint-privacy' (#55) from feature/46-imprint-privacy into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #55
close #46
2021-01-30 15:16:46 +00:00
philipp 901c7c1241 load version on DOMContentLoaded
ref #56
2021-01-30 16:16:30 +01:00
philipp 4e82369b16 text selection color
ref #46
2021-01-30 16:14:38 +01:00
philipp 945963db32 Footer linking
ref #46
2021-01-29 19:07:46 +01:00
philipp 5741cbe756 added Privacy page
ref #46
2021-01-29 19:02:53 +01:00
philipp 6401aeb3a8 working Imprint page
ref #46
2021-01-29 18:49:02 +01:00
philipp 6a0c129d39 added basic styling to Imprint component
ref #46
2021-01-29 17:58:52 +01:00
philipp bbec9ffcdf added Imprint route /imprint
ref #46
2021-01-29 17:58:22 +01:00
philipp 541f1fa2e3 Merge pull request 'feature/44-require-mail-addresses' (#54) from feature/44-require-mail-addresses into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #54
close #44
2021-01-29 15:38:06 +00:00
philipp 7897820632 UserDetail - invalid email UI feedback
ref #44
2021-01-29 16:34:55 +01:00
philipp 0dd9de2abc UserDetail - enforce email input
ref #44
2021-01-27 18:48:23 +01:00
philipp 7131ba99b6 AddUserModal - enforce email input
ref #44
2021-01-27 18:45:36 +01:00
philipp c69026aa5b Merge pull request 'feature/45-component-drop' (#53) from feature/45-component-drop into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #53
close #45
2021-01-27 17:42:08 +00:00
philipp 16ac96c64e 🧹 remove placeholder options from Dashboard sidebar
ref #45
2021-01-27 18:26:46 +01:00
philipp 1bb79b1c98 🧹 remove ComponentDump from MainDashContent
ref #45
2021-01-27 18:26:26 +01:00
philipp eeee272f03 🧹 drop old + unused components Dash + LoginAlt
ref #45
2021-01-27 18:26:04 +01:00
philipp 2563e9d1d6 🚀RELEASE v0.5.0
continuous-integration/drone/push Build is passing
2021-01-26 18:29:39 +01:00
philipp 24bec66390 🐞 fix package release for index template compatibility 2021-01-26 18:29:26 +01:00
philipp 3d30734dc2 new license file version [CI SKIP] 2021-01-26 17:26:12 +00:00
philipp cbc1d53cc2 🐞 fixed merge conflict errors
continuous-integration/drone/push Build is passing
ref #13 #12
2021-01-26 18:25:30 +01:00
philipp 9a1f7a13f8 general dependency bump 2021-01-26 18:25:02 +01:00
philipp d48b9b7f91 Merge pull request 'feature/12-user-management' (#39) from feature/12-user-management into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #39
close #12
2021-01-26 16:28:59 +00:00
philipp 358865dc6a UserDetail - update permission badges on change save
ref #12
2021-01-26 17:28:07 +01:00
philipp e750c37473 🌎 UserDetail - more i18n keys
ref #12
2021-01-26 17:27:44 +01:00
philipp 71a589c10c Merge branch 'dev' into feature/12-user-management
# Conflicts:
#	src/App.svelte
2021-01-26 17:00:21 +01:00
philipp 3281239ff5 new license file version [CI SKIP] 2021-01-26 15:59:14 +00:00
philipp 3e2cdddd5a Merge pull request 'feature/13-runner-management' (#42) from feature/13-runner-management into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #42
close #13
2021-01-26 15:58:28 +00:00
philipp 1d4c3e51c7 Merge branch 'dev' into feature/13-runner-management 2021-01-26 15:57:55 +00:00
philipp 1694c71528 AddRunnerModal - improved team select
ref #13
2021-01-26 16:54:15 +01:00
philipp 169ffc1b0b 🌎 added more i18n keys
ref #13
2021-01-26 16:53:59 +01:00
philipp 89eb3259d4 Merge pull request 'added permissions to dashboard sidebar' (#41) from feature/40-dynamic-sidebar-options into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #41
close #41
2021-01-26 15:42:02 +00:00
philipp ffd88ffc66 🐞 alphabetically sort permission targets in UserDetail
ref #39 ref #12
2021-01-25 20:56:20 +01:00
philipp 6c2d13bd17 🌎 last i18n keys
ref #13
2021-01-25 20:39:34 +01:00
philipp 8d92a75ef0 🏃‍♂️ support for runner group edit
ref #13
2021-01-25 20:39:22 +01:00
philipp acb86ae266 added permissions to dashboard sidebar
ref #40
2021-01-25 20:20:58 +01:00
niggl 473cf978b4 Merge branch 'dev' into feature/12-user-management
# Conflicts:
#	src/components/UserDetail.svelte
2021-01-24 21:50:38 +01:00
philipp 4debab2636 Merge branch 'dev' into feature/13-runner-management
# Conflicts:
#	package.json
2021-01-24 20:39:11 +01:00
philipp e91e197873 new license file version [CI SKIP] 2021-01-24 19:39:09 +00:00
philipp b30b6734a1 general dependency bump
continuous-integration/drone/push Build is passing
2021-01-24 20:38:29 +01:00
philipp dadb80608a 💣 process breaking changes for lib v0.3.0
continuous-integration/drone/push Build is failing
2021-01-24 20:37:56 +01:00
philipp 16c9969fb9 Merge branch 'feature/13-runner-management' of https://git.odit.services/lfk/frontend into feature/13-runner-management 2021-01-24 18:41:04 +01:00
philipp dc1644ed25 🐞 ImportRunnerModal - table overflow fix
ref #13
2021-01-24 18:40:54 +01:00
philipp 2cc9b3e1ed 👀 ImportRunnerModal - layout cleanup
ref #13
2021-01-24 18:38:16 +01:00
niggl 415f340a68 i18n 🌍
ref #13
2021-01-24 18:20:48 +01:00
philipp 2d4869128d 🌎 i18n
ref #13
2021-01-24 17:54:45 +01:00
philipp ae8bc01d9b 🌎 i18n
ref #13
2021-01-24 17:47:29 +01:00
philipp e2552d9442 Merge branch 'dev' into feature/13-runner-management 2021-01-24 17:41:11 +01:00
philipp 5d1b5d80b6 Merge branch 'feature/13-runner-management' of https://git.odit.services/lfk/frontend into feature/13-runner-management 2021-01-24 17:31:31 +01:00
philipp 366804aa29 🌎 i18n
ref #13
2021-01-24 17:31:10 +01:00
philipp 9240e0c903 🧹 general runner cleanup
ref #13
2021-01-24 17:30:31 +01:00
niggl 7baaf2cff3 Merge branch 'feature/13-runner-management' of git.odit.services:lfk/frontend into feature/13-runner-management 2021-01-24 17:23:18 +01:00
niggl 9fbc1ba031 Added friles to ignore 2021-01-24 17:21:48 +01:00
niggl 6704c07db0 Deleted files to ignore 2021-01-24 17:21:39 +01:00
philipp a87165148a 🧹 RunnerDetail cleanup + i18n 🌎
ref #13
2021-01-24 17:21:19 +01:00
philipp ec4bcd093b 🐞 [bugfix] RunnerDetail update
ref #13
2021-01-24 17:16:49 +01:00
philipp 5552055b98 RunnerDetail - button text fixes
ref #13
2021-01-21 20:50:14 +01:00
philipp 03aa67034d basic RunnerDetail
ref #13
2021-01-21 19:07:43 +01:00
philipp fc21427685 💻 updated VSCode recommended extensions
continuous-integration/drone/push Build is passing
change i18n-ally scoping
2021-01-21 18:41:05 +01:00
philipp 819b02a204 ImportRunnerModal - hide team when loading from TeamDetail
ref #13
2021-01-20 20:25:41 +01:00
philipp de0bd5fd57 ImportRunnerModal usage in TeamDetail
ref #13
2021-01-20 20:21:59 +01:00
philipp 8aa1d94a1a use ImportRunnerModal in OrgDetail + Orgs
ref #13
2021-01-20 19:59:53 +01:00
philipp f8a59133a2 ImportRunnerModal - compatibility for multi-component access
ref #13
2021-01-20 19:59:31 +01:00
philipp c382f770dc 👀 basic ui interaction for ImportRunnerModal
ref #13
2021-01-20 18:31:23 +01:00
philipp cde4ec13ef basic cancel event dispatch from ImportRunnerModal
ref #13
2021-01-20 18:15:47 +01:00
philipp ecad1ea839 ↙ added default fallback parsing to ImportRunnerModal
ref #13
2021-01-20 17:56:32 +01:00
philipp 6b91b22713 🚀 ImportRunnerModal - working demo
ref #13
2021-01-20 17:46:18 +01:00
philipp e34c91b2cc 🌎 i18n in ImportRunnerModal headers
ref #13
2021-01-20 17:33:10 +01:00
philipp 822759a688 😦 added missing dependencies
ref #13
2021-01-19 21:45:00 +01:00
philipp b606037890 🌎 added locale based csv/xlsx header parsing
ref #13
2021-01-19 21:44:41 +01:00
philipp 74d9b94119 basic xlsx + csv parsing
ref #13
2021-01-19 21:44:13 +01:00
philipp b1e9f955b0 basic ImportRunnerModal with CSV input
ref #13
2021-01-19 18:19:21 +01:00
philipp e0356fa360 fixed runner permissions
ref #13
2021-01-19 18:18:51 +01:00
philipp fbc67eeb98 Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev 2021-01-18 20:34:50 +01:00
philipp 09fd73b130 🐞 improved version builder from template 2021-01-18 20:34:47 +01:00
philipp 259a76f46b 🧹 darkmode classes cleanup 2021-01-18 20:29:44 +01:00
philipp c6504c2eaf new license file version [CI SKIP] 2021-01-17 18:46:15 +00:00
philipp 7d104a1514 🚀RELEASE v0.4.0
continuous-integration/drone/push Build is passing
2021-01-17 19:45:28 +01:00
philipp b3bd61c89e Merge branch 'feature/13-runner-management' into dev
continuous-integration/drone/push Build was killed
2021-01-17 19:44:07 +01:00
philipp e49dca0275 🐞 gitignore fix 2021-01-17 19:29:05 +01:00
philipp 03125b3a2d general dependency bumps 2021-01-17 19:24:57 +01:00
philipp a523379b3a gitignore fix 2021-01-17 19:24:25 +01:00
philipp aa6348a29a fix package:dev script
continuous-integration/drone/push Build is passing
ref #37
2021-01-17 19:22:45 +01:00
philipp b9f0f1a69a Merge commit 'a284806d3cb769030a4e28d0403190b746f8fc61' into dev
continuous-integration/drone/push Build is passing
close #37
2021-01-17 19:18:42 +01:00
philipp a284806d3c re-enable PWA functionality via serviceworker
ref #37
2021-01-17 19:15:22 +01:00
philipp 7e10c1db65 🔨 cleaned up build process + Dockerfile
ref #37
2021-01-17 19:14:14 +01:00
philipp 11790638d6 🔨 cleaned up build process + Dockerfile
continuous-integration/drone/push Build is passing
2021-01-17 19:01:11 +01:00
philipp 0583cbe266 improved serviceworker + PWA logic
continuous-integration/drone/push Build was killed
2021-01-17 18:59:26 +01:00
philipp 2e6874c822 apply new gitignore config 2021-01-17 18:32:32 +01:00
philipp 2ce41990bf 🐞 fix cross-env logic for faster dev starts 2021-01-17 18:31:35 +01:00
philipp c8aeba38ba Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
continuous-integration/drone/push Build is failing
2021-01-17 18:22:57 +01:00
philipp 5e02502a5c 👩‍💻 developer configs/ recommendations for VSCode 2021-01-17 18:22:28 +01:00
philipp 382cc3d844 new license file version [CI SKIP] 2021-01-17 17:19:48 +00:00
philipp dd74d9ee89 🧹 gitignore changes in public/index.html & svelte.config.js
continuous-integration/drone/push Build is failing
2021-01-17 18:19:07 +01:00
philipp 383f82807f improved dev scripts for speed starts
continuous-integration/drone/push Build was killed
2021-01-17 18:16:02 +01:00
philipp d4579a9a41 dynamic contact info in AddRunnerModal
ref #13
2021-01-17 17:54:21 +01:00
philipp 66a07c6a51 RunnersOverview
ref #13
2021-01-17 17:51:03 +01:00
philipp 66ffd8e936 AddRunnerModal
ref #13
2021-01-17 17:50:52 +01:00
philipp 44f07ca231 🧹 AddUserModal cleanup 2021-01-17 17:23:26 +01:00
philipp ff14f024af AddUserModal - username/email validation
ref #12
2021-01-17 17:14:34 +01:00
philipp dccf7c6c8d PWA optimizations
continuous-integration/drone/push Build is passing
2021-01-17 15:59:28 +01:00
philipp 10d7955f99 UserPermissions - working edit
ref #12
2021-01-16 21:42:09 +01:00
philipp 64ade901de 🚀RELEASE v0.3.1
continuous-integration/drone/push Build is passing
2021-01-16 20:59:45 +01:00
philipp eb0dd3f781 🤝 attribution/ credits for icons and illustrations
continuous-integration/drone/push Build was killed
2021-01-16 20:59:08 +01:00
philipp 66e6cd80d3 added new empty states
continuous-integration/drone/push Build was killed
2021-01-16 20:49:29 +01:00
philipp 959b32de1c new UsersEmptyState
ref #12
2021-01-16 20:48:45 +01:00
philipp 9c6dc5b424 basic UserPermissions view
ref #12
2021-01-16 20:33:34 +01:00
philipp aaab95d414 UserDetail - link to permission page
ref #12
2021-01-16 18:30:35 +01:00
philipp 7d4e93912c UserDetail - basic permission badges
ref #12
2021-01-16 18:23:28 +01:00
philipp d65b463547 UserDetail - add permission layout
ref #12
2021-01-16 17:31:17 +01:00
philipp 6e5a4bcb39 formatting
ref #12
2021-01-16 17:19:03 +01:00
niggl 1a799dc30a Fixed User group update
ref #12
2021-01-16 17:17:56 +01:00
philipp e3d2676858 Merge branch 'dev' into feature/12-user-management 2021-01-16 17:11:10 +01:00
philipp 42851686ca Merge pull request 'feature/14-team-management' (#36) from feature/14-team-management into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #36
closee #14
2021-01-16 15:29:47 +00:00
philipp e3943d868a 🐞 fix deletion in TeamDetail + TeamsOverview
ref #14
2021-01-16 16:27:06 +01:00
philipp 7654b795c7 🧹 TeamDetail cleanup
ref #14
2021-01-16 16:21:56 +01:00
philipp 489244f1a9 🔒 ConfirmTeamDeletion in TeamDetail
ref #14
2021-01-15 23:05:36 +01:00
philipp cbcce336d6 🔒 ConfirmTeamDeletion in TeamsOverview
ref #14
2021-01-15 23:02:40 +01:00
philipp 52a96b2a4f Merge pull request 'feature/16-org-management' (#35) from feature/16-org-management into dev
continuous-integration/drone/push Build is passing
Reviewed-on: #35
close #16
2021-01-15 21:55:48 +00:00
philipp ce6002a631 🔒 re-enable confirmation in OrgOverview
ref #16
2021-01-15 22:50:56 +01:00
philipp 84a9cf069a UX - ConfirmOrgDeletion cancel event reflection in datatable
ref #16
2021-01-15 22:49:16 +01:00
philipp 83f19a7572 🔒 ConfirmOrgDeletion in OrgOverview
ref #16
2021-01-15 22:35:40 +01:00
philipp a1a4c8b56d Merge branch 'feature/14-team-management' into feature/16-org-management 2021-01-15 22:31:56 +01:00
philipp d8901126d0 🔒 ConfirmOrgDeletion in OrgDetail
ref #16
2021-01-15 22:30:38 +01:00
philipp 854db4ece8 🧹 drop tmp modification from UsersOverview
ref #14
2021-01-15 22:05:39 +01:00
philipp 07f2e65fc7 🧹 Team cleanups
ref #14
2021-01-15 22:04:21 +01:00
philipp ccf09f97d5 TeamDetail with edit,delete
ref #14
2021-01-15 22:01:43 +01:00
philipp 8f9a4ebc04 Merge branch 'dev' into feature/14-team-management 2021-01-15 21:48:34 +01:00
philipp f1833f13d5 🧹 Dashboard - drop header bar
continuous-integration/drone/push Build was killed
2021-01-15 21:48:11 +01:00
philipp 6a81e369fa 🐞 fix Dashboard sidebar responsiveness
continuous-integration/drone/push Build was killed
drop entire js logic - css only
2021-01-15 21:42:17 +01:00
philipp 597e9e1ea9 basic TeamsOverview
ref #14
2021-01-15 21:22:51 +01:00
philipp 9bb027ec4c AddTeamModal working
ref #14
2021-01-15 21:22:37 +01:00
philipp fbbbaa5d49 Merge branch 'dev' into feature/14-team-management 2021-01-15 20:37:30 +01:00
philipp aaec5a3fc9 new license file version [CI SKIP] 2021-01-15 19:21:12 +00:00
philipp 7cd24cd51d 🚀RELEASE v0.3.0
continuous-integration/drone/push Build is passing
2021-01-15 20:20:02 +01:00
philipp c81b34c1d0 Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
continuous-integration/drone/push Build was killed
2021-01-15 20:19:03 +01:00
philipp 7b1acc494d Merge pull request 'feature/16-org-management' (#32) from feature/16-org-management into dev
continuous-integration/drone/push Build was killed
Reviewed-on: #32
 close #16
2021-01-15 19:18:52 +00:00
philipp 6ff90694e2 bump gridjs to 3.2.2 2021-01-15 20:17:36 +01:00
philipp 157c7c66b5 🧹 general component cleanup
continuous-integration/drone/push Build was killed
2021-01-15 20:14:54 +01:00
philipp 93249258c6 🏁 finish basic functionality of AddOrgModal + OrgDetail
ref #16
2021-01-15 20:03:29 +01:00
philipp 01c01a46fa 🌎 i18n
ref #16
2021-01-15 19:25:42 +01:00
philipp 0e2a10fe94 basic functionality in OrgDetail
ref #16
2021-01-15 19:25:30 +01:00
philipp 0b9f3de47c improvements in OrgOverview
ref #16
2021-01-15 19:25:12 +01:00
philipp bc239eead1 💬 AddOrgModal bindings
ref #16
2021-01-15 19:24:46 +01:00
philipp 7a09869b0c 🏬 OrgDetail ui
ref #16
2021-01-15 19:14:46 +01:00
philipp bdc0de6ada added Org base components
ref #16
2021-01-15 18:49:45 +01:00
philipp 6870a7f9b1 🧹 TeamsOverview - formatting
ref #14
2021-01-15 17:51:12 +01:00
philipp ace1a1b063 🐞 fix component mount in TeamsEmptyState
ref #14
2021-01-15 17:11:04 +01:00
philipp d87b879cc3 🏃‍♂️🏃‍♂️🏃‍♂️ basic UI components for team management
ref #14
2021-01-14 19:10:43 +01:00
philipp 65b36f8e69 🙋‍♂️🔒 UserDetail - permission layout ui
ref #12
2021-01-14 18:56:28 +01:00
philipp 87387a54f2 Merge branch 'dev' into feature/12-user-management 2021-01-14 18:30:08 +01:00
philipp b497cebe76 Merge commit 'fcd657c10ea14290455cfb0bf2de89375a664143' into dev
continuous-integration/drone/push Build is passing
close #31
2021-01-14 18:26:33 +01:00
philipp 0fa107a75b [tmp] - disable serviceworker 2021-01-14 18:25:01 +01:00
philipp b34e3aeed0 👀 UsersOverview - disable advanced search
ref #12
2021-01-14 18:24:37 +01:00
philipp 35b18d72fd Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
continuous-integration/drone/push Build is passing
2021-01-14 18:22:54 +01:00
philipp 4b80f30afb 🐳 Dockerfile - drop js sourcemaps 2021-01-14 18:22:33 +01:00
philipp 86c54e04a8 🙋‍♂️ UserDetail - active/inactive user state edit
ref #12
2021-01-14 18:22:09 +01:00
philipp ef9fc596f5 🙋‍♂️ UserDetail - disable profile picture edit
ref #12
2021-01-14 18:21:48 +01:00
philipp ad34e455ce new license file version [CI SKIP] 2021-01-14 17:18:21 +00:00
philipp 01fdd0bee2 Bump Dockerfile builder to 15.5.1-alpine3.12
continuous-integration/drone/push Build is passing
2021-01-14 18:17:29 +01:00
philipp 32ffa345cd 🔨 config compatibility for new Snowpack V3 bundler
continuous-integration/drone/push Build is failing
2021-01-14 18:17:12 +01:00
philipp 6fc3c16073 basic dependency bump
continuous-integration/drone/push Build is failing
lfk-library, snowpack@3.0.10 & svelte plugin
2021-01-14 18:16:46 +01:00
philipp 7d58657c80 🔨 reorder CI build order for correct license exporting
continuous-integration/drone/push Build is passing
2021-01-13 21:38:05 +01:00
philipp fcd657c10e 🐞 fix sidebar mobile-md scaling
ref #31
2021-01-13 21:37:29 +01:00
philipp 4ab77c5557 Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
continuous-integration/drone/push Build is passing
2021-01-13 21:07:08 +01:00
philipp 87926e69db new license file version [CI SKIP] 2021-01-12 20:07:09 +00:00
204 changed files with 30739 additions and 5137 deletions
+5
View File
@@ -0,0 +1,5 @@
FROM mcr.microsoft.com/vscode/devcontainers/base:alpine-3.12
RUN apk update
RUN apk add --upgrade nodejs-current npm
RUN npm i -g pnpm rimraf
RUN rimraf node_modules
+20
View File
@@ -0,0 +1,20 @@
{
"name": "Node.js",
"build": {
"dockerfile": "Dockerfile"
},
"settings": {
"terminal.integrated.shell.linux": "/bin/sh"
},
"extensions": [
"dbaeumer.vscode-eslint",
"2gua.rainbow-brackets",
"christian-kohler.npm-intellisense",
"remimarsal.prettier-now",
"svelte.svelte-vscode",
"lokalise.i18n-ally",
"fivethree.vscode-svelte-snippets",
"voorjaar.windicss-intellisense"
],
"postCreateCommand": "yarn && yarn dev --open"
}
+3 -2
View File
@@ -1,3 +1,4 @@
public/env.sample.js
public/workbox-*.js
public/workbox-*.js.map
.pnpm-store
.yarn
.pnp.*
-41
View File
@@ -1,41 +0,0 @@
---
kind: pipeline
type: docker
name: build:dev
steps:
- name: build dev
image: plugins/docker
depends_on: [clone]
settings:
username:
from_secret: DOCKER_REGISTRY_USER
password:
from_secret: DOCKER_REGISTRY_PASSWORD
repo: registry.odit.services/lfk/frontend
tags:
- dev
registry: registry.odit.services
- name: run full license export
depends_on: ["clone"]
image: node:alpine
commands:
- yarn
- yarn licenses:export
- name: push new licenses file to repo
depends_on: ["run full license export"]
image: appleboy/drone-git-push
settings:
branch: dev
commit: true
commit_message: new license file version [CI SKIP]
author_email: bot@odit.services
remote: git@git.odit.services:lfk/frontend.git
ssh_key:
from_secret: GITLAB_SSHKEY
trigger:
branch:
- dev
event:
- push
+34
View File
@@ -0,0 +1,34 @@
name: Build Latest and dev images
on:
push:
branches:
- dev
jobs:
build-container:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 19
- run: npm i -g pnpm@8 && pnpm i
- run: pnpm licenses:export
- name: Login to registry
uses: docker/login-action@v3
with:
registry: registry.odit.services
username: ${{ vars.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
tags: |
${{ vars.REGISTRY }}/lfk/frontend:dev
${{ vars.REGISTRY }}/lfk/frontend:latest
platforms: linux/amd64,linux/arm64
+33
View File
@@ -0,0 +1,33 @@
name: Build release images
on:
push:
tags:
- "*.*.*"
jobs:
build-container:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 19
- run: npm i -g pnpm@8 && pnpm i
- run: pnpm licenses:export
- name: Login to registry
uses: docker/login-action@v3
with:
registry: registry.odit.services
username: ${{ vars.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
tags: |
${{ vars.REGISTRY }}/lfk/frontend:${{ github.ref_name }}
platforms: linux/amd64,linux/arm64
+6 -8
View File
@@ -1,10 +1,8 @@
.vscode
.idea
node_modules
dist
dist-ssr
public/env.js
/build
yarn.lock
package-lock.json
*.map
public/env.js
public/index.html
/dist
.pnpm-store
.yarn
.pnp.*
+12
View File
@@ -0,0 +1,12 @@
{
"recommendations": [
"2gua.rainbow-brackets",
"christian-kohler.npm-intellisense",
"remimarsal.prettier-now",
"svelte.svelte-vscode",
"lokalise.i18n-ally",
"fivethree.vscode-svelte-snippets",
"voorjaar.windicss-intellisense"
],
"unwantedRecommendations": ["antfu.i18n-ally"]
}
+7
View File
@@ -0,0 +1,7 @@
languageIds:
- javascript
- svelte
- html
monopoly: false
refactorTemplates:
- "{$_('$1')}"
+5
View File
@@ -0,0 +1,5 @@
{
"i18n-ally.localesPaths": "src/locales",
"i18n-ally.keystyle": "nested",
"windicss.enableCodeFolding": false
}
+1608 -1
View File
File diff suppressed because it is too large Load Diff
+11 -14
View File
@@ -1,19 +1,16 @@
FROM node:15.4.0-alpine3.12
FROM registry.odit.services/hub/library/node:23.10.0-alpine3.21 AS build
ARG NPM_REGISTRY_URL=https://registry.npmjs.org
WORKDIR /app
RUN npm i -g pnpm
COPY package.json ./
RUN pnpm i
COPY package.json *.config.js workbox-config.js ./
COPY package.json pnpm-lock.yaml vite.config.js tailwind.config.cjs postcss.config.cjs index.html ./
RUN npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@9
RUN mkdir /pnpm && pnpm config set store-dir /pnpm && pnpm i
COPY src ./src
COPY public ./public
RUN pnpm run build:sw
RUN pnpm run build
RUN pnpm build
# final image
FROM alpine
COPY --from=0 /app/build /app
RUN rm -rf /app/build/_dist_/components
RUN rm -rf /app/build/_dist_/locales
RUN rm -rf /app/build-manifest.json
FROM fholzer/nginx-brotli:v1.19.1
COPY --from=1 /app /usr/share/nginx/html
FROM registry.odit.services/library/nginx-brotli:3.15 AS final
COPY --from=build /app/dist /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/nginx.conf
+362
View File
@@ -0,0 +1,362 @@
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Creative
Commons Corporation ("Creative Commons") is not a law firm and does not provide
legal services or legal advice. Distribution of Creative Commons public licenses
does not create a lawyer-client or other relationship. Creative Commons makes
its licenses and related information available on an "as-is" basis. Creative
Commons gives no warranties regarding its licenses, any material licensed
under their terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the fullest
extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and conditions
that creators and other rights holders may use to share original works of
authorship and other material subject to copyright and certain other rights
specified in the public license below. The following considerations are for
informational purposes only, are not exhaustive, and do not form part of our
licenses.
Considerations for licensors: Our public licenses are intended for use by
those authorized to give the public permission to use material in ways otherwise
restricted by copyright and certain other rights. Our licenses are irrevocable.
Licensors should read and understand the terms and conditions of the license
they choose before applying it. Licensors should also secure all rights necessary
before applying our licenses so that the public can reuse the material as
expected. Licensors should clearly mark any material not subject to the license.
This includes other CC-licensed material, or material used under an exception
or limitation to copyright. More considerations for licensors : wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public licenses, a licensor
grants the public permission to use the licensed material under specified
terms and conditions. If the licensor's permission is not necessary for any
reasonfor example, because of any applicable exception or limitation to copyrightthen
that use is not regulated by the license. Our licenses grant only permissions
under copyright and certain other rights that a licensor has authority to
grant. Use of the licensed material may still be restricted for other reasons,
including because others have copyright or other rights in the material. A
licensor may make special requests, such as asking that all changes be marked
or described. Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More considerations for the public
: wiki.creativecommons.org/Considerations_for_licensees
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public
License
By exercising the Licensed Rights (defined below), You accept and agree to
be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike
4.0 International Public License ("Public License"). To the extent this Public
License may be interpreted as a contract, You are granted the Licensed Rights
in consideration of Your acceptance of these terms and conditions, and the
Licensor grants You such rights in consideration of benefits the Licensor
receives from making the Licensed Material available under these terms and
conditions.
Section 1 Definitions.
a. Adapted Material means material subject to Copyright and Similar Rights
that is derived from or based upon the Licensed Material and in which the
Licensed Material is translated, altered, arranged, transformed, or otherwise
modified in a manner requiring permission under the Copyright and Similar
Rights held by the Licensor. For purposes of this Public License, where the
Licensed Material is a musical work, performance, or sound recording, Adapted
Material is always produced where the Licensed Material is synched in timed
relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright and Similar
Rights in Your contributions to Adapted Material in accordance with the terms
and conditions of this Public License.
c. BY-NC-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses,
approved by Creative Commons as essentially the equivalent of this Public
License.
d. Copyright and Similar Rights means copyright and/or similar rights closely
related to copyright including, without limitation, performance, broadcast,
sound recording, and Sui Generis Database Rights, without regard to how the
rights are labeled or categorized. For purposes of this Public License, the
rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
e. Effective Technological Measures means those measures that, in the absence
of proper authority, may not be circumvented under laws fulfilling obligations
under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996,
and/or similar international agreements.
f. Exceptions and Limitations means fair use, fair dealing, and/or any other
exception or limitation to Copyright and Similar Rights that applies to Your
use of the Licensed Material.
g. License Elements means the license attributes listed in the name of a Creative
Commons Public License. The License Elements of this Public License are Attribution,
NonCommercial, and ShareAlike.
h. Licensed Material means the artistic or literary work, database, or other
material to which the Licensor applied this Public License.
i. Licensed Rights means the rights granted to You subject to the terms and
conditions of this Public License, which are limited to all Copyright and
Similar Rights that apply to Your use of the Licensed Material and that the
Licensor has authority to license.
j. Licensor means the individual(s) or entity(ies) granting rights under this
Public License.
k. NonCommercial means not primarily intended for or directed towards commercial
advantage or monetary compensation. For purposes of this Public License, the
exchange of the Licensed Material for other material subject to Copyright
and Similar Rights by digital file-sharing or similar means is NonCommercial
provided there is no payment of monetary compensation in connection with the
exchange.
l. Share means to provide material to the public by any means or process that
requires permission under the Licensed Rights, such as reproduction, public
display, public performance, distribution, dissemination, communication, or
importation, and to make material available to the public including in ways
that members of the public may access the material from a place and at a time
individually chosen by them.
m. Sui Generis Database Rights means rights other than copyright resulting
from Directive 96/9/EC of the European Parliament and of the Council of 11
March 1996 on the legal protection of databases, as amended and/or succeeded,
as well as other essentially equivalent rights anywhere in the world.
n. You means the individual or entity exercising the Licensed Rights under
this Public License. Your has a corresponding meaning.
Section 2 Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License, the Licensor
hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive,
irrevocable license to exercise the Licensed Rights in the Licensed Material
to:
A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial
purposes only; and
B. produce, reproduce, and Share Adapted Material for NonCommercial purposes
only.
2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions
and Limitations apply to Your use, this Public License does not apply, and
You do not need to comply with its terms and conditions.
3. Term. The term of this Public License is specified in Section 6(a).
4. Media and formats; technical modifications allowed. The Licensor authorizes
You to exercise the Licensed Rights in all media and formats whether now known
or hereafter created, and to make technical modifications necessary to do
so. The Licensor waives and/or agrees not to assert any right or authority
to forbid You from making technical modifications necessary to exercise the
Licensed Rights, including technical modifications necessary to circumvent
Effective Technological Measures. For purposes of this Public License, simply
making modifications authorized by this Section 2(a)(4) never produces Adapted
Material.
5. Downstream recipients.
A. Offer from the Licensor Licensed Material. Every recipient of the Licensed
Material automatically receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this Public License.
B. Additional offer from the Licensor Adapted Material. Every recipient
of Adapted Material from You automatically receives an offer from the Licensor
to exercise the Licensed Rights in the Adapted Material under the conditions
of the Adapter's License You apply.
C. No downstream restrictions. You may not offer or impose any additional
or different terms or conditions on, or apply any Effective Technological
Measures to, the Licensed Material if doing so restricts exercise of the Licensed
Rights by any recipient of the Licensed Material.
6. No endorsement. Nothing in this Public License constitutes or may be construed
as permission to assert or imply that You are, or that Your use of the Licensed
Material is, connected with, or sponsored, endorsed, or granted official status
by, the Licensor or others designated to receive attribution as provided in
Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not licensed under this
Public License, nor are publicity, privacy, and/or other similar personality
rights; however, to the extent possible, the Licensor waives and/or agrees
not to assert any such rights held by the Licensor to the limited extent necessary
to allow You to exercise the Licensed Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this Public License.
3. To the extent possible, the Licensor waives any right to collect royalties
from You for the exercise of the Licensed Rights, whether directly or through
a collecting society under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly reserves any right
to collect such royalties, including when the Licensed Material is used other
than for NonCommercial purposes.
Section 3 License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the following
conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified form), You must:
A. retain the following if it is supplied by the Licensor with the Licensed
Material:
i. identification of the creator(s) of the Licensed Material and any others
designated to receive attribution, in any reasonable manner requested by the
Licensor (including by pseudonym if designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of warranties;
v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
B. indicate if You modified the Licensed Material and retain an indication
of any previous modifications; and
C. indicate the Licensed Material is licensed under this Public License, and
include the text of, or the URI or hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner
based on the medium, means, and context in which You Share the Licensed Material.
For example, it may be reasonable to satisfy the conditions by providing a
URI or hyperlink to a resource that includes the required information.
3. If requested by the Licensor, You must remove any of the information required
by Section 3(a)(1)(A) to the extent reasonably practicable.
b. ShareAlike.In addition to the conditions in Section 3(a), if You Share
Adapted Material You produce, the following conditions also apply.
1. The Adapter's License You apply must be a Creative Commons license with
the same License Elements, this version or later, or a BY-NC-SA Compatible
License.
2. You must include the text of, or the URI or hyperlink to, the Adapter's
License You apply. You may satisfy this condition in any reasonable manner
based on the medium, means, and context in which You Share Adapted Material.
3. You may not offer or impose any additional or different terms or conditions
on, or apply any Effective Technological Measures to, Adapted Material that
restrict exercise of the rights granted under the Adapter's License You apply.
Section 4 Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that apply to
Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract,
reuse, reproduce, and Share all or a substantial portion of the contents of
the database for NonCommercial purposes only;
b. if You include all or a substantial portion of the database contents in
a database in which You have Sui Generis Database Rights, then the database
in which You have Sui Generis Database Rights (but not its individual contents)
is Adapted Material, including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share all or
a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not replace
Your obligations under this Public License where the Licensed Rights include
other Copyright and Similar Rights.
Section 5 Disclaimer of Warranties and Limitation of Liability.
a. Unless otherwise separately undertaken by the Licensor, to the extent possible,
the Licensor offers the Licensed Material as-is and as-available, and makes
no representations or warranties of any kind concerning the Licensed Material,
whether express, implied, statutory, or other. This includes, without limitation,
warranties of title, merchantability, fitness for a particular purpose, non-infringement,
absence of latent or other defects, accuracy, or the presence or absence of
errors, whether or not known or discoverable. Where disclaimers of warranties
are not allowed in full or in part, this disclaimer may not apply to You.
b. To the extent possible, in no event will the Licensor be liable to You
on any legal theory (including, without limitation, negligence) or otherwise
for any direct, special, indirect, incidental, consequential, punitive, exemplary,
or other losses, costs, expenses, or damages arising out of this Public License
or use of the Licensed Material, even if the Licensor has been advised of
the possibility of such losses, costs, expenses, or damages. Where a limitation
of liability is not allowed in full or in part, this limitation may not apply
to You.
c. The disclaimer of warranties and limitation of liability provided above
shall be interpreted in a manner that, to the extent possible, most closely
approximates an absolute disclaimer and waiver of all liability.
Section 6 Term and Termination.
a. This Public License applies for the term of the Copyright and Similar Rights
licensed here. However, if You fail to comply with this Public License, then
Your rights under this Public License terminate automatically.
b. Where Your right to use the Licensed Material has terminated under Section
6(a), it reinstates:
1. automatically as of the date the violation is cured, provided it is cured
within 30 days of Your discovery of the violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any right the
Licensor may have to seek remedies for Your violations of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the Licensed Material
under separate terms or conditions or stop distributing the Licensed Material
at any time; however, doing so will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
Section 7 Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different terms or
conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the Licensed
Material not stated herein are separate from and independent of the terms
and conditions of this Public License.
Section 8 Interpretation.
a. For the avoidance of doubt, this Public License does not, and shall not
be interpreted to, reduce, limit, restrict, or impose conditions on any use
of the Licensed Material that could lawfully be made without permission under
this Public License.
b. To the extent possible, if any provision of this Public License is deemed
unenforceable, it shall be automatically reformed to the minimum extent necessary
to make it enforceable. If the provision cannot be reformed, it shall be severed
from this Public License without affecting the enforceability of the remaining
terms and conditions.
c. No term or condition of this Public License will be waived and no failure
to comply consented to unless expressly agreed to by the Licensor.
d. Nothing in this Public License constitutes or may be interpreted as a limitation
upon, or waiver of, any privileges and immunities that apply to the Licensor
or You, including from the legal processes of any jurisdiction or authority.
Creative Commons is not a party to its public licenses. Notwithstanding, Creative
Commons may elect to apply one of its public licenses to material it publishes
and in those instances will be considered the "Licensor." The text of the
Creative Commons public licenses is dedicated to the public domain under the
CC0 Public Domain Dedication. Except for the limited purpose of indicating
that material is shared under a Creative Commons public license or as otherwise
permitted by the Creative Commons policies published at creativecommons.org/policies,
Creative Commons does not authorize the use of the trademark "Creative Commons"
or any other trademark or logo of Creative Commons without its prior written
consent including, without limitation, in connection with any unauthorized
modifications to any of its public licenses or any other arrangements, understandings,
or agreements concerning use of licensed material. For the avoidance of doubt,
this paragraph does not form part of the public licenses.
Creative Commons may be contacted at creativecommons.org.
+27
View File
@@ -0,0 +1,27 @@
# @odit/lfk-frontend
## ✒️ Overview
This is an API client for [https://git.odit.services/lfk/backend](@lfk/backend)
This application is intended for use by admin users/ members only.
## 🚀 Getting Started
```
pnpm i
```
## Development
```
pnpm dev
/
pnpm dev --open
```
## Build
```
pnpm build
```
+6 -6
View File
@@ -1,8 +1,8 @@
version: "3"
services:
httpd:
build: .
volumes:
- ./public/env.sample.js:/usr/share/nginx/html/env.js
ports:
- 4050:80
httpd:
build: .
volumes:
- ./public/env.sample.js:/usr/share/nginx/html/env.js
ports:
- 4050:80
-6
View File
@@ -1,6 +0,0 @@
const config = {
baseurl: 'https://dev.lauf-fuer-kaya.de',
fallback_username: 'admin',
fallback_password: '72fpTzsev4xUu78QPs2FCbwZ3',
prefersHashRouting: true
};
+22
View File
@@ -0,0 +1,22 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.png" />
<link rel="manifest" href="/manifest.webmanifest" />
<link rel="apple-touch-icon" href="/lfk-logo.png" />
<meta name="theme-color" content="#FFFFFF" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Lauf Für Kaya! - Admin" />
<title>Lauf für Kaya! - Admin</title>
</head>
<body>
<span style="display: none; visibility: hidden" id="buildinfo"
>RELEASE_INFO-1.8.2-RELEASE_INFO</span
>
<noscript>You need to enable JavaScript to run this app.</noscript>
<script src="/env.js"></script>
<script type="module" src="/src/main.js"></script>
</body>
</html>
+14
View File
@@ -6,6 +6,20 @@ http {
server {
error_page 404 /index.html;
root /usr/share/nginx/html;
location /assets {
expires 1y;
log_not_found off;
access_log off;
}
location = /index.html {
add_header Cache-Control 'no-store';
}
location = / {
add_header Cache-Control 'no-store';
}
location = /env.js {
add_header Cache-Control 'no-store';
}
location / {
try_files $uri $uri/ /index.html;
}
+15 -13
View File
@@ -1,16 +1,18 @@
const fs = require('fs');
import fs from "fs";
// get all language files
const files = fs.readdirSync('./src/locales/');
const files = fs.readdirSync("./src/locales/");
files.forEach((f) => {
// read file as object
const unordered = JSON.parse(fs.readFileSync(`src/locales/${f}`));
// order object by keys alpabetically A-Z
const ordered = Object.keys(unordered).sort().reduce((obj, key) => {
obj[key] = unordered[key];
return obj;
}, {});
// format output as json for commit diff compatibility
const out = JSON.stringify(ordered, 0, 4);
// write output file
fs.writeFileSync(`src/locales/${f}`, out);
// read file as object
const unordered = JSON.parse(fs.readFileSync(`src/locales/${f}`));
// order object by keys alpabetically A-Z
const ordered = Object.keys(unordered)
.sort()
.reduce((obj, key) => {
obj[key] = unordered[key];
return obj;
}, {});
// format output as json for commit diff compatibility
const out = JSON.stringify(ordered, 0, 4);
// write output file
fs.writeFileSync(`src/locales/${f}`, out);
});
+62 -54
View File
@@ -1,56 +1,64 @@
{
"name": "@odit/lfk-frontend",
"version": "0.2.1",
"scripts": {
"i18n-order": "node order.js",
"dev": "snowpack dev",
"build": "snowpack build",
"build:sw": "workbox generateSW workbox-config.js",
"release": "release-it",
"licenses:export": "license-exporter --json -o public"
},
"dependencies": {
"@odit/lfk-client-js": "0.0.11",
"filepond": "4.25.1",
"gridjs": "3.2.1",
"localforage": "1.9.0",
"lodash.isequal": "^4.5.0",
"svelte-filepond": "0.0.1",
"svelte-focus-trap": "1.0.1",
"svelte-i18n": "3.3.0",
"tailwindcss": "2.0.2",
"tinro": "0.5.6",
"toastify-js": "1.9.3",
"validator": "13.5.2"
},
"devDependencies": {
"@odit/license-exporter": "0.0.9",
"@snowpack/plugin-svelte": "3.4.1",
"auto-changelog": "^2.2.1",
"autoprefixer": "10.2.1",
"postcss": "8.2.4",
"postcss-load-config": "3.0.0",
"release-it": "^14.2.2",
"snowpack": "3.0.0-rc.2",
"svelte": "3.31.2",
"svelte-preprocess": "4.6.1",
"workbox-cli": "6.0.2"
},
"release-it": {
"git": {
"commit": true,
"requireCleanWorkingDir": false,
"commitMessage": "🚀RELEASE v${version}",
"push": false,
"tag": true,
"tagName": null,
"tagAnnotation": "v${version}"
},
"npm": {
"publish": false
},
"hooks": {
"after:bump": "npx auto-changelog --commit-limit false -p -u --hide-credit && git add CHANGELOG.md && node versionbuilder.js && git add public/index.html && node order.js && git add src/locales"
}
}
"name": "@odit/lfk-frontend",
"version": "1.8.2",
"type": "module",
"scripts": {
"i18n-order": "node order.js",
"dev": "vite",
"format": "prettier --write --plugin-search-dir=. .",
"build": "vite build",
"release": "release-it",
"licenses:export": "license-exporter --json -o public"
},
"license": "CC-BY-NC-SA-4.0",
"devDependencies": {
"@odit/license-exporter": "0.2.0",
"@sveltejs/vite-plugin-svelte": "2.1.1",
"auto-changelog": "2.5.0",
"autoprefixer": "10.4.21",
"postcss": "8.5.3",
"prettier": "3.5.3",
"prettier-plugin-svelte": "3.3.3",
"release-it": "17.10.0",
"svelte-select": "3.17.0",
"tailwindcss": "3.4.15",
"vite": "4.3.3"
},
"release-it": {
"git": {
"commit": true,
"requireCleanWorkingDir": false,
"commitMessage": "🚀RELEASE v${version}",
"push": true,
"tag": true,
"tagName": null,
"tagAnnotation": "v${version}"
},
"npm": {
"publish": false
},
"hooks": {
"after:bump": "npx auto-changelog --commit-limit false -p -u --hide-credit && git add CHANGELOG.md && node versionbuilder.js && git add index.html && node order.js && git add src/locales"
}
},
"dependencies": {
"@fontsource/athiti": "^5.2.5",
"@odit/lfk-client-js": "1.1.3",
"@paralleldrive/cuid2": "2.2.2",
"@tanstack/svelte-table": "8.9.1",
"bwip-js": "3.4.0",
"check-password-strength": "2.0.10",
"csvtojson": "2.0.10",
"localforage": "1.10.0",
"marked": "4.3.0",
"svelte": "3.58.0",
"svelte-french-toast": "1.2.0",
"svelte-i18n": "3.6.0",
"tinro": "0.6.12",
"validator": "13.15.0",
"xlsx": "0.18.5"
},
"volta": {
"node": "20.0.0"
}
}
+5123
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
+10 -3
View File
@@ -1,5 +1,12 @@
const config = {
baseurl: 'http://localhost:4010',
// optional
prefersHashRouting: true
baseurl: "http://localhost:4010",
baseurl_selfservice: "http://localhost:5174",
baseurl_documentserver: "http://localhost:4010/documents",
documentserver_key:
"NqZSYTy5AFQ7MppbLW5moqpTk7u7YrNUHKYhKYuThnnya2WpCOIU694hIZT1FzYe",
// optional
default_username: "demo",
default_password: "demo",
prefersHashRouting: true,
};
window.config = config;
-22
View File
@@ -1,22 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.png" />
<link rel="manifest" href="/manifest.webmanifest">
<link rel="apple-touch-icon" href="/lfk-logo.png">
<meta name="theme-color" content="#FFFFFF">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Lauf Für Kaya! - Admin" />
<title>Lauf für Kaya! - Admin</title>
</head>
<body>
<span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.2.1-RELEASE_INFO</span>
<noscript>You need to enable JavaScript to run this app.</noscript>
<script src="/env.js"></script>
<script defer type="module" src="/_dist_/index.js"></script>
</body>
</html>
+265 -1
View File
File diff suppressed because one or more lines are too long
+37 -25
View File
@@ -1,27 +1,39 @@
{
"name": "Lauf für Kaya! - Admin",
"short_name": "LfK!Admin",
"start_url": ".",
"display": "standalone",
"background_color": "#fff",
"theme_color": "#fff",
"description": "Lauf für Kaya! - Admin",
"icons": [
{
"src": "/favicon.png",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "/favicon.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "/lfk-logo.png",
"sizes": "1540x144",
"type": "image/png"
},
{ "src": "/maskable_icon_x1.png", "sizes": "750x750", "type": "image/png", "purpose": "any maskable" }
]
"name": "Lauf für Kaya! - Admin",
"short_name": "LfK!Admin",
"start_url": "/?utm_source=pwa",
"orientation": "portrait-primary",
"display": "standalone",
"background_color": "#fff",
"theme_color": "#fff",
"description": "Lauf für Kaya! - Admin",
"shortcuts": [
{
"name": "Users",
"url": "/users/?utm_source=pwa"
}
],
"icons": [
{
"src": "/favicon.png",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "/favicon.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "/lfk-logo.png",
"sizes": "1540x144",
"type": "image/png"
},
{
"src": "/maskable_icon_x1.png",
"sizes": "750x750",
"type": "image/png",
"purpose": "any maskable"
}
]
}
+1
View File
@@ -0,0 +1 @@
Nostrud tempor dolor aute ea excepteur aute mollit elit eiusmod exercitation. Magna laborum pariatur adipisicing pariatur cupidatat exercitation duis aliquip pariatur sint exercitation deserunt labore. Consectetur id laboris dolore nostrud do velit ipsum. Eu laboris velit do commodo ad ea sint ex cillum. Cillum ipsum qui eiusmod laborum mollit sunt dolore incididunt. Cillum sunt culpa veniam voluptate et qui ut magna anim occaecat ut mollit dolor. Duis irure proident eu incididunt dolore sunt nisi aute dolore amet eu fugiat laboris quis.
-2
View File
@@ -1,2 +0,0 @@
if(!self.define){const e=e=>{"require"!==e&&(e+=".js");let r=Promise.resolve();return i[e]||(r=new Promise((async r=>{if("document"in self){const i=document.createElement("script");i.src=e,document.head.appendChild(i),i.onload=r}else importScripts(e),r()}))),r.then((()=>{if(!i[e])throw new Error(`Module ${e} didnt register its module`);return i[e]}))},r=(r,i)=>{Promise.all(r.map(e)).then((e=>i(1===e.length?e[0]:e)))},i={require:Promise.resolve(r)};self.define=(r,s,o)=>{i[r]||(i[r]=Promise.resolve().then((()=>{let i={};const c={uri:location.origin+r.slice(1)};return Promise.all(s.map((r=>{switch(r){case"exports":return i;case"module":return c;default:return e(r)}}))).then((e=>{const r=o(...e);return i.default||(i.default=r),i}))})))}}define("./sw.js",["./workbox-c8ead010"],(function(e){"use strict";self.addEventListener("message",(e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()})),e.precacheAndRoute([{url:"favicon.ico",revision:"ba44f340afba5bb1a07f14decc15dd04"},{url:"favicon.png",revision:"07a9941cec62319578fa2a1734db9959"},{url:"favicon.svg",revision:"689d6c6fda51e359c0e5725d9e905064"},{url:"index.html",revision:"931c34f3675364dcc09411aa0f223776"},{url:"logo.svg",revision:"4c9e31a1f4268d7e36e22cda7656e561"},{url:"manifest.webmanifest",revision:"75c93eb352c4877216e77b1d7f73445f"},{url:"robots.txt",revision:"61c27d2cd39a713f7829422c3d9edcc7"}],{})}));
//# sourceMappingURL=sw.js.map
File diff suppressed because one or more lines are too long
-30
View File
@@ -1,30 +0,0 @@
/** @type {import("snowpack").SnowpackUserConfig } */
module.exports = {
mount: {
public: '/',
src: '/_dist_'
},
plugins: [ '@snowpack/plugin-svelte' ],
install: [
/* ... */
],
installOptions: {
/* ... */
sourceMap: false
},
devOptions: {
/* ... */
},
buildOptions: {
/* ... */
},
proxy: {
/* ... */
},
alias: {
/* ... */
},
experiments: {
optimize: { bundle: true, minify: true }
}
};
+149 -31
View File
@@ -1,6 +1,4 @@
<script>
import "./TailwindStyles.svelte";
import "toastify-js/src/toastify.css";
import { Route, router } from "tinro";
router.subscribe((routeInfo) => {
window.scrollTo(0, 0);
@@ -24,43 +22,79 @@
name: "lfk_admin",
version: 1.0,
storeName: "lfk_admin",
description: "LfK! admin dashbaord",
description: "LfK! admin dashboard",
});
window.onunhandledrejection = (event) => {
if (event.reason.toString() == "Error: Unauthorized") {
localForage.clear();
location.replace("/");
}
};
//
import Login from "./components/Login.svelte";
import Dashboard from "./components/Dashboard.svelte";
import Login from "./components/auth/Login.svelte";
import Dashboard from "./components/dashboard/Dashboard.svelte";
import store from "./store.js";
import NotFound from "./components/NotFound.svelte";
import ForgotPassword from "./components/ForgotPassword.svelte";
import MainDashContent from "./components/MainDashContent.svelte";
import Users from "./components/Users.svelte";
import About from "./components/About.svelte";
import Settings from "./components/Settings.svelte";
import Transition from "./components/Transition.svelte";
import Orgs from "./components/Orgs.svelte";
import Runners from "./components/Runners.svelte";
import Footer from "./components/Footer.svelte";
import Tracks from "./components/Tracks.svelte";
import TracksOverview from "./components/TracksOverview.svelte";
import OrgDetail from "./components/OrgDetail.svelte";
import Teams from "./components/Teams.svelte";
import { OpenAPI, AuthService } from "@odit/lfk-client-js";
import UserDetail from "./components/UserDetail.svelte";
import ForgotPassword from "./components/auth/ForgotPassword.svelte";
import MainDashContent from "./components/dashboard/MainDashContent.svelte";
import Users from "./components/users/Users.svelte";
import About from "./components/general/About.svelte";
import Settings from "./components/settings/Settings.svelte";
import Transition from "./components/base/Transition.svelte";
import Orgs from "./components/orgs/Orgs.svelte";
import Runners from "./components/runners/Runners.svelte";
import Footer from "./components/general/Footer.svelte";
import TracksOverview from "./components/tracks/TracksOverview.svelte";
import OrgDetail from "./components/orgs/OrgDetail.svelte";
import Teams from "./components/teams/Teams.svelte";
import { OpenAPI } from "@odit/lfk-client-js";
import UserDetail from "./components/users/UserDetail.svelte";
OpenAPI.BASE = config.baseurl;
import { register as registerSW } from "./swmodule";
import TeamDetail from "./components/teams/TeamDetail.svelte";
import UserPermissions from "./components/users/UserPermissions.svelte";
import GroupPermissions from "./components/groups/GroupPermissions.svelte";
import RunnerDetail from "./components/runners/RunnerDetail.svelte";
import Imprint from "./components/general/Imprint.svelte";
import Privacy from "./components/general/Privacy.svelte";
import ResetPassword from "./components/auth/ResetPassword.svelte";
import Contacts from "./components/contacts/Contacts.svelte";
import ContactDetail from "./components/contacts/ContactDetail.svelte";
import Donors from "./components/donors/Donors.svelte";
import Groups from "./components/groups/Groups.svelte";
import DonorDetail from "./components/donors/DonorDetail.svelte";
import Donations from "./components/donations/Donations.svelte";
import DonationDetail from "./components/donations/DonationDetail.svelte";
import GroupDetail from "./components/groups/GroupDetail.svelte";
import ScanStations from "./components/scanstations/ScanStations.svelte";
import ScanStationDetail from "./components/scanstations/ScanStationDetail.svelte";
import Scans from "./components/scans/Scans.svelte";
import ScanDetail from "./components/scans/ScanDetail.svelte";
import Cards from "./components/cards/Cards.svelte";
import StatsClients from "./components/statsclients/StatsClients.svelte";
import StatsClientDetail from "./components/statsclients/StatsClientDetail.svelte";
store.init();
registerSW();
</script>
<Route>
{#if $router.path === '/forgot_password'}
{#if $router.path === "/forgot_password"}
<Route path="/forgot_password">
<ForgotPassword />
</Route>
{:else if $router.path === '/about'}
{:else if $router.path.includes("/reset")}
<Route path="/reset/:resetkey" let:params>
<ResetPassword {params} />
</Route>
{:else if $router.path === "/about"}
<Route path="/about">
<About />
</Route>
{:else if $router.path === "/imprint"}
<Route path="/imprint">
<Imprint />
</Route>
{:else if $router.path === "/privacy"}
<Route path="/privacy">
<Privacy />
</Route>
{:else if $store.isLoggedIn}
<Dashboard>
<Transition>
@@ -71,8 +105,26 @@
<Route path="/">
<Users />
</Route>
<Route path="/:userid" let:params>
<UserDetail {params} />
<Route path="/:userid/*" let:params>
<Route path="/">
<UserDetail {params} />
</Route>
<Route path="/permissions/">
<UserPermissions {params} />
</Route>
</Route>
</Route>
<Route path="/groups/*">
<Route path="/">
<Groups />
</Route>
<Route path="/:groupid/*" let:params>
<Route path="/">
<GroupDetail {params} />
</Route>
<Route path="/permissions/">
<GroupPermissions {params} />
</Route>
</Route>
</Route>
<Route path="/tracks/*">
@@ -81,11 +133,29 @@
</Route>
<Route path="/:trackid" let:params />
</Route>
<Route path="/runners">
<Runners />
<Route path="/runners/*">
<Route path="/">
<Runners />
</Route>
<Route path="/:runnerid" let:params>
<RunnerDetail {params} />
</Route>
</Route>
<Route path="/teams">
<Teams />
<Route path="/teams/*">
<Route path="/">
<Teams />
</Route>
<Route path="/:teamid" let:params>
<TeamDetail {params} />
</Route>
</Route>
<Route path="/contacts/*">
<Route path="/">
<Contacts />
</Route>
<Route path="/:contact" let:params>
<ContactDetail {params} />
</Route>
</Route>
<Route path="/orgs/*">
<Route path="/">
@@ -95,6 +165,54 @@
<OrgDetail {params} />
</Route>
</Route>
<Route path="/donors/*">
<Route path="/">
<Donors />
</Route>
<Route path="/:donorid" let:params>
<DonorDetail {params} />
</Route>
</Route>
<Route path="/donations/*">
<Route path="/">
<Donations />
</Route>
<Route path="/:donationid" let:params>
<DonationDetail {params} />
</Route>
</Route>
<Route path="/cards/*">
<Route path="/">
<Cards />
</Route>
<!-- <Route path="/:scanid" let:params>
<ScanDetail {params} />
</Route> -->
</Route>
<Route path="/scans/*">
<Route path="/">
<Scans />
</Route>
<Route path="/:scanid" let:params>
<ScanDetail {params} />
</Route>
</Route>
<Route path="/scanstations/*">
<Route path="/">
<ScanStations />
</Route>
<Route path="/:stationid" let:params>
<ScanStationDetail {params} />
</Route>
</Route>
<Route path="/statsclients/*">
<Route path="/">
<StatsClients />
</Route>
<Route path="/:clientid" let:params>
<StatsClientDetail {params} />
</Route>
</Route>
<Route path="/about">
<About />
</Route>
-6
View File
@@ -1,6 +0,0 @@
<style global>
/*! @import */
@tailwind base;
@tailwind components;
@tailwind utilities;
</style>
-194
View File
@@ -1,194 +0,0 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "./outsideclick";
import { focusTrap } from "svelte-focus-trap";
export let modal_open;
(function () {
document.onkeydown = function (e) {
e = e || window.event;
if (e.key === "Escape") {
modal_open = false;
}
};
})();
const license_promise = fetch("/licenses.json");
let licenses = [];
$: currentlicense = "";
$: licensetext = "";
license_promise
.then((response) => response.json())
.then((json) => {
licenses = json;
});
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop" />
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span>
<div
class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline">
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10">
<svg
fill="currentColor"
class="h-6 w-6 text-blue-600"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"><path fill="none" d="M0 0h24v24H0z" />
<path
d="M14 20v2H2v-2h12zM14.586.686l7.778 7.778L20.95 9.88l-1.06-.354L17.413 12l5.657 5.657-1.414 1.414L16 13.414l-2.404 2.404.283 1.132-1.415 1.414-7.778-7.778 1.415-1.414 1.13.282 6.294-6.293-.353-1.06L14.586.686z" /></svg>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium">
{$_('read-license')}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">{currentlicense}</p>
</div>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">{licensetext}</p>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
{$_('close')}
</button>
</div>
</div>
</div>
</div>
{/if}
<!-- /// -->
<div class="pt-12 px-4 sm:px-6 lg:px-8 lg:pt-20 bg-gray-900 pb-12">
<div class="text-center mb-8">
<h1
class="mt-9 font-display text-4xl leading-none font-semibold text-white sm:text-5xl lg:text-6xl">
{$_('about')}
🧾
</h1>
<p
class="mt-2 max-w-xl mx-auto text-xl lg:max-w-3xl lg:text-2xl text-gray-300">
Lauf für Kaya!
<strong class="text-white font-medium">
{$_('by')}
<a href="https://odit.services" class="underline">ODIT.Services</a>
</strong>
<br />
<span class="text-lg">{$_('lfk-is-os')}</span>
</p>
</div>
</div>
<div class="pt-0 pb-16 overflow-hidden lg:pt-12 lg:py-24">
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
<h2 class="text-4xl font-display font-semibold md:text-5xl">
{$_('credits')}
</h2>
<div class="max-w-3xl mx-auto text-xl leading-8 font-medium mt-8">
<p class="text-center">{$_('oss_credit_description')}</p>
</div>
<div class="w-screen leading-8 pl-5 mt-5">
{#await license_promise}
<p class="text-center w-full">{$_('licenses-are-being-loaded')}</p>
{:then}
<table>
<thead>
<tr>
<th>{$_('dependency_name')}</th>
<th>{$_('license')}</th>
<th>{$_('repo_link')}</th>
<th>{$_('installed-version')}</th>
<th>{$_('author')}</th>
</tr>
</thead>
<tbody>
{#each licenses as l}
<tr>
<td>{l.name}</td>
<td>
{l.license || '?'}<br /><span
class="underline cursor-pointer"
on:click={() => {
modal_open = true;
currentlicense = l.name + '@' + l.version;
licensetext = l.licensetext || $_('no-license-text-could-be-found');
}}>{$_('read-license')}</span>
</td>
<td>
{(l.repo?.url || l.repo)
.replace('git+', '')
.replace('git://', '')}
</td>
<td>{l.version || '?'}</td>
<td>{l.author?.name || l.author || '?'}</td>
</tr>
{/each}
</tbody>
</table>
{:catch error}
<div
class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500">
<span class="inline-block align-middle mr-8">
<b class="capitalize">{$_('general_promise_error')}</b>
{error}
</span>
</div>
{/await}
</div>
<h2 class="text-4xl font-display font-semibold md:text-5xl">{$_('faq')}</h2>
<div class="mt-6 border-t-2 border-gray-100 pt-10">
<dl class="md:grid md:grid-cols-2 md:gap-8">
<div>
<div>
<dt class="text-lg leading-6 font-medium">Q</dt>
<dd class="mt-2">
<p class="text-base text-gray-500">A</p>
</dd>
</div>
</div>
<div class="mt-12 sm:mt-0">
<div id="team-pricing">
<dt class="text-lg leading-6 font-medium">Q</dt>
<dd class="mt-2">
<p class="text-base text-gray-500">A</p>
</dd>
</div>
<div class="mt-12">
<dt class="text-lg leading-6 font-medium">Q</dt>
<dd class="mt-2">
<p class="text-base text-gray-500">A</p>
</dd>
</div>
</div>
</dl>
</div>
</div>
</div>
-281
View File
@@ -1,281 +0,0 @@
<div class="w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890">
<div class="flex flex-row items-center justify-between mb-6">
<div class="flex flex-col">
<div class="text-sm font-light text-grey-500">Conversions</div>
<div class="text-sm font-bold"><span>This year</span></div>
</div>
<div class="relative"><button
class="btn btn-default btn-circle btn-icon bg-transparent hover:bg-transparent active:bg-transparent relative"><svg
stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round"
stroke-linejoin="round" class="stroke-current stroke-1" size="18" height="18" width="18"
xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="1"></circle>
<circle cx="12" cy="5" r="1"></circle>
<circle cx="12" cy="19" r="1"></circle>
</svg></button>
<div class="dropdown absolute top-0 right-0 mt-8 ">
<div class="dropdown-content w-48 bottom-start">
<div class="flex flex-col w-full">
<ul class="list-none">
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
href="/">Today</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
href="/">This week</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
href="/">This month</a></li>
<li><a
class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100 dark:bg-grey-895 dark:hover:bg-grey-890"
href="/">This year</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="flex flex-row w-full">
<div style="width:100%;height:240px">
<div class="recharts-responsive-container" style="width:100%;height:100%">
<div class="recharts-wrapper"
style="position: relative; cursor: default; width: 704px; height: 240px;"><svg
class="recharts-surface" width="704" height="240" viewBox="0 0 704 240" version="1.1">
<defs>
<clipPath id="recharts3-clip">
<rect x="40" y="10" height="190" width="654"></rect>
</clipPath>
</defs>
<g class="recharts-layer recharts-cartesian-axis recharts-xAxis xAxis">
<g class="recharts-cartesian-axis-ticks">
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="654" height="30" x="67.25"
y="208" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value"
text-anchor="middle">
<tspan x="67.25" dy="0.71em">Jan</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="654" height="30"
x="121.75" y="208" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="121.75" dy="0.71em">Feb</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="654" height="30"
x="176.25" y="208" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="176.25" dy="0.71em">Mar</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="654" height="30"
x="230.75" y="208" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="230.75" dy="0.71em">Apr</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="654" height="30"
x="285.25" y="208" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="285.25" dy="0.71em">May</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="654" height="30"
x="339.75" y="208" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="339.75" dy="0.71em">Jun</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="654" height="30"
x="394.25" y="208" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="394.25" dy="0.71em">Jul</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="654" height="30"
x="448.75" y="208" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="448.75" dy="0.71em">Aug</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="654" height="30"
x="503.25" y="208" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="503.25" dy="0.71em">Sep</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="654" height="30"
x="557.75" y="208" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="557.75" dy="0.71em">Oct</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="654" height="30"
x="612.25" y="208" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="612.25" dy="0.71em">Nov</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="654" height="30"
x="666.75" y="208" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="666.75" dy="0.71em">Dec</tspan>
</text></g>
</g>
</g>
<g class="recharts-layer recharts-cartesian-axis recharts-yAxis yAxis">
<g class="recharts-cartesian-axis-ticks">
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="30" height="190" x="32"
y="200" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value"
text-anchor="end">
<tspan x="32" dy="0.355em">0</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="30" height="190" x="32"
y="152.5" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="end">
<tspan x="32" dy="0.355em">65</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="30" height="190" x="32"
y="105" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value"
text-anchor="end">
<tspan x="32" dy="0.355em">130</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="30" height="190" x="32"
y="57.5" stroke="none" fill="#666"
class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="end">
<tspan x="32" dy="0.355em">195</tspan>
</text></g>
<g class="recharts-layer recharts-cartesian-axis-tick"><text width="30" height="190" x="32"
y="10" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value"
text-anchor="end">
<tspan x="32" dy="0.355em">260</tspan>
</text></g>
</g>
</g>
<g class="recharts-layer recharts-bar">
<g class="recharts-layer recharts-bar-rectangles">
<g class="recharts-layer">
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#90caf9" width="10" height="119.11538461538461" x="55" y="80.88461538461539"
radius="0" class="recharts-rectangle"
d="M 55,80.88461538461539 h 10 v 119.11538461538461 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#90caf9" width="10" height="95" x="109.5" y="105" radius="0"
class="recharts-rectangle" d="M 109.5,105 h 10 v 95 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#90caf9" width="10" height="122.03846153846155" x="164" y="77.96153846153845"
radius="0" class="recharts-rectangle"
d="M 164,77.96153846153845 h 10 v 122.03846153846155 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#90caf9" width="10" height="81.11538461538461" x="218.5"
y="118.88461538461539" radius="0" class="recharts-rectangle"
d="M 218.5,118.88461538461539 h 10 v 81.11538461538461 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#90caf9" width="10" height="114" x="273" y="86" radius="0"
class="recharts-rectangle" d="M 273,86 h 10 v 114 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#90caf9" width="10" height="117.65384615384616" x="327.5"
y="82.34615384615384" radius="0" class="recharts-rectangle"
d="M 327.5,82.34615384615384 h 10 v 117.65384615384616 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#90caf9" width="10" height="103.76923076923076" x="382" y="96.23076923076924"
radius="0" class="recharts-rectangle"
d="M 382,96.23076923076924 h 10 v 103.76923076923076 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#90caf9" width="10" height="92.80769230769232" x="436.5"
y="107.19230769230768" radius="0" class="recharts-rectangle"
d="M 436.5,107.19230769230768 h 10 v 92.80769230769232 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#90caf9" width="10" height="92.80769230769232" x="491" y="107.19230769230768"
radius="0" class="recharts-rectangle"
d="M 491,107.19230769230768 h 10 v 92.80769230769232 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#90caf9" width="10" height="127.8846153846154" x="545.5" y="72.1153846153846"
radius="0" class="recharts-rectangle"
d="M 545.5,72.1153846153846 h 10 v 127.8846153846154 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#90caf9" width="10" height="105.23076923076924" x="600" y="94.76923076923076"
radius="0" class="recharts-rectangle"
d="M 600,94.76923076923076 h 10 v 105.23076923076924 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#90caf9" width="10" height="115.46153846153845" x="654.5"
y="84.53846153846155" radius="0" class="recharts-rectangle"
d="M 654.5,84.53846153846155 h 10 v 115.46153846153845 h -10 Z"></path>
</g>
</g>
</g>
</g>
<g class="recharts-layer recharts-bar">
<g class="recharts-layer recharts-bar-rectangles">
<g class="recharts-layer">
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#1e88e5" width="10" height="112.53846153846155" x="69" y="87.46153846153845"
radius="0" class="recharts-rectangle"
d="M 69,87.46153846153845 h 10 v 112.53846153846155 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#1e88e5" width="10" height="151.26923076923077" x="123.5"
y="48.730769230769226" radius="0" class="recharts-rectangle"
d="M 123.5,48.730769230769226 h 10 v 151.26923076923077 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#1e88e5" width="10" height="181.23076923076923" x="178" y="18.769230769230774"
radius="0" class="recharts-rectangle"
d="M 178,18.769230769230774 h 10 v 181.23076923076923 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#1e88e5" width="10" height="165.8846153846154" x="232.5" y="34.11538461538461"
radius="0" class="recharts-rectangle"
d="M 232.5,34.11538461538461 h 10 v 165.8846153846154 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#1e88e5" width="10" height="156.38461538461536" x="287" y="43.61538461538464"
radius="0" class="recharts-rectangle"
d="M 287,43.61538461538464 h 10 v 156.38461538461536 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#1e88e5" width="10" height="118.38461538461539" x="341.5"
y="81.61538461538461" radius="0" class="recharts-rectangle"
d="M 341.5,81.61538461538461 h 10 v 118.38461538461539 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#1e88e5" width="10" height="138.84615384615384" x="396" y="61.15384615384616"
radius="0" class="recharts-rectangle"
d="M 396,61.15384615384616 h 10 v 138.84615384615384 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#1e88e5" width="10" height="175.3846153846154" x="450.5"
y="24.615384615384613" radius="0" class="recharts-rectangle"
d="M 450.5,24.615384615384613 h 10 v 175.3846153846154 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#1e88e5" width="10" height="155.65384615384613" x="505" y="44.34615384615387"
radius="0" class="recharts-rectangle"
d="M 505,44.34615384615387 h 10 v 155.65384615384613 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#1e88e5" width="10" height="179.76923076923077" x="559.5"
y="20.230769230769226" radius="0" class="recharts-rectangle"
d="M 559.5,20.230769230769226 h 10 v 179.76923076923077 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#1e88e5" width="10" height="173.19230769230768" x="614" y="26.80769230769232"
radius="0" class="recharts-rectangle"
d="M 614,26.80769230769232 h 10 v 173.19230769230768 h -10 Z"></path>
</g>
<g class="recharts-layer recharts-bar-rectangle">
<path fill="#1e88e5" width="10" height="146.15384615384616" x="668.5"
y="53.84615384615384" radius="0" class="recharts-rectangle"
d="M 668.5,53.84615384615384 h 10 v 146.15384615384616 h -10 Z"></path>
</g>
</g>
</g>
</g>
</svg>
<div class="recharts-tooltip-wrapper"
style="pointer-events: none; visibility: hidden; position: absolute; top: 0px; transform: translate(538.875px, 126px);">
</div>
</div>
<div style="position:absolute;width:0;height:0;visibility:hidden;display:none"></div>
</div>
</div>
</div>
</div>
File diff suppressed because it is too large Load Diff
-359
View File
@@ -1,359 +0,0 @@
<script>
import { _ } from "svelte-i18n";
import { active } from "tinro";
import localForage from "localforage";
import { router } from "tinro";
import store from "../store";
import NoComponentLoaded from "./NoComponentLoaded.svelte";
import { AuthService, OpenAPI } from "@odit/lfk-client-js";
let activePage = "dashboard";
let dropdown1 = false;
let navOpen = false;
function ismobile() {
let check = false;
(function (a) {
if (
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(
a
) ||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
a.substr(0, 4)
)
)
check = true;
})(navigator.userAgent || navigator.vendor || window.opera);
return check;
}
$: mobile = ismobile();
function logout() {
localForage.clear();
location.replace("/");
}
</script>
<section class="min-h-screen bg-gray-50 dark:bg-black dark:text-gray-100">
<nav
class:hidden={!navOpen && mobile}
class="select-none fixed top-0 left-0 z-20 h-full pb-10 overflow-x-hidden overflow-y-auto transition origin-left transform border-r w-60 md:translate-x-0">
<a href="/" class="flex items-center px-4 py-5">
<img
src="/lfk-logo.png"
alt="Logo"
class="h-10" />
<h3 class="text-lg">Lauf für Kaya! Admin</h3>
</a>
<nav class="text-sm font-medium text-gray-600" aria-label="Main Navigation">
<a
class:dark:bg-gray-900={$router.path === '/'}
class:bg-gray-100={$router.path === '/'}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
href="/">
<svg
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor">
<path
d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z" />
</svg>
<span>{$_('dashboard-title')}</span>
</a>
<a
class:dark:bg-gray-900={$router.path.includes('/orgs/')}
class:bg-gray-100={$router.path.includes('/orgs/')}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
href="/orgs/">
<svg
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"><path fill="none" d="M0 0h24v24H0z" />
<path
d="M17 19h2v-8h-6v8h2v-6h2v6zM3 19V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v5h2v10h1v2H2v-2h1zm4-8v2h2v-2H7zm0 4v2h2v-2H7zm0-8v2h2V7H7z" /></svg>
<span>{$_('orgs')}</span>
</a>
<a
class:dark:bg-gray-900={$router.path === '/users/'}
class:bg-gray-100={$router.path === '/users/'}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
href="/users/">
<svg
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 640 512"><path
fill="currentColor"
d="M610.5 341.3c2.6-14.1 2.6-28.5 0-42.6l25.8-14.9c3-1.7 4.3-5.2 3.3-8.5-6.7-21.6-18.2-41.2-33.2-57.4-2.3-2.5-6-3.1-9-1.4l-25.8 14.9c-10.9-9.3-23.4-16.5-36.9-21.3v-29.8c0-3.4-2.4-6.4-5.7-7.1-22.3-5-45-4.8-66.2 0-3.3.7-5.7 3.7-5.7 7.1v29.8c-13.5 4.8-26 12-36.9 21.3l-25.8-14.9c-2.9-1.7-6.7-1.1-9 1.4-15 16.2-26.5 35.8-33.2 57.4-1 3.3.4 6.8 3.3 8.5l25.8 14.9c-2.6 14.1-2.6 28.5 0 42.6l-25.8 14.9c-3 1.7-4.3 5.2-3.3 8.5 6.7 21.6 18.2 41.1 33.2 57.4 2.3 2.5 6 3.1 9 1.4l25.8-14.9c10.9 9.3 23.4 16.5 36.9 21.3v29.8c0 3.4 2.4 6.4 5.7 7.1 22.3 5 45 4.8 66.2 0 3.3-.7 5.7-3.7 5.7-7.1v-29.8c13.5-4.8 26-12 36.9-21.3l25.8 14.9c2.9 1.7 6.7 1.1 9-1.4 15-16.2 26.5-35.8 33.2-57.4 1-3.3-.4-6.8-3.3-8.5l-25.8-14.9zM496 368.5c-26.8 0-48.5-21.8-48.5-48.5s21.8-48.5 48.5-48.5 48.5 21.8 48.5 48.5-21.7 48.5-48.5 48.5zM96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm224 32c1.9 0 3.7-.5 5.6-.6 8.3-21.7 20.5-42.1 36.3-59.2 7.4-8 17.9-12.6 28.9-12.6 6.9 0 13.7 1.8 19.6 5.3l7.9 4.6c.8-.5 1.6-.9 2.4-1.4 7-14.6 11.2-30.8 11.2-48 0-61.9-50.1-112-112-112S208 82.1 208 144c0 61.9 50.1 112 112 112zm105.2 194.5c-2.3-1.2-4.6-2.6-6.8-3.9-8.2 4.8-15.3 9.8-27.5 9.8-10.9 0-21.4-4.6-28.9-12.6-18.3-19.8-32.3-43.9-40.2-69.6-10.7-34.5 24.9-49.7 25.8-50.3-.1-2.6-.1-5.2 0-7.8l-7.9-4.6c-3.8-2.2-7-5-9.8-8.1-3.3.2-6.5.6-9.8.6-24.6 0-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h255.4c-3.7-6-6.2-12.8-6.2-20.3v-9.2zM173.1 274.6C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg>
<span>{$_('users')}</span>
</a>
<a
class:dark:bg-gray-900={$router.path === '/runners/'}
class:bg-gray-100={$router.path === '/runners/'}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
href="/runners/">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"><path fill="none" d="M0 0h24v24H0z" />
<path
d="M9.83 8.79L8 9.456V13H6V8.05h.015l5.268-1.918c.244-.093.51-.14.782-.131a2.616 2.616 0 0 1 2.427 1.82c.186.583.356.977.51 1.182A4.992 4.992 0 0 0 19 11v2a6.986 6.986 0 0 1-5.402-2.547l-.581 3.297L15 15.67V23h-2v-5.986l-2.05-1.987-.947 4.298-6.894-1.215.348-1.97 4.924.868L9.83 8.79zM13.5 5.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4z" /></svg>
<span>{$_('runners')}</span>
</a>
<a
class:dark:bg-gray-900={$router.path === '/teams/'}
class:bg-gray-100={$router.path === '/teams/'}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
href="/teams/">
<svg
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 640 512"><path
fill="currentColor"
d="M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg>
<span>{$_('teams')}</span>
</a>
<a
class:dark:bg-gray-900={$router.path === '/tracks/'}
class:bg-gray-100={$router.path === '/tracks/'}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
href="/tracks/">
<svg
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 640 512"><path
fill="currentColor"
d="M635.7 167.2L556.1 31.7c-8.8-15-28.3-20.1-43.5-11.5l-69 39.1L503.3 161c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L416 75l-55.2 31.3 27.9 47.4c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L333.2 122 278 153.3 337.8 255c2.2 3.7.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9l-59.7-101.7-55.2 31.3 27.9 47.4c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9l-27.9-47.5-55.2 31.3 59.7 101.7c2.2 3.7.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L84.9 262.9l-69 39.1C.7 310.7-4.6 329.8 4.2 344.8l79.6 135.6c8.8 15 28.3 20.1 43.5 11.5L624.1 210c15.2-8.6 20.4-27.8 11.6-42.8z" /></svg>
<span>{$_('tracks')}</span>
</a>
<a
class:dark:bg-gray-900={activePage === 'blub'}
class:bg-gray-100={activePage === 'blub'}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
href="#">
<svg
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor">
<path d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z" />
<path
fill-rule="evenodd"
d="M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm9.707 5.707a1 1 0 00-1.414-1.414L9 12.586l-1.293-1.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
clip-rule="evenodd" />
</svg>
<span>Checklists</span>
</a>
<div>
<div
tabindex="0"
class:dark:bg-gray-900={activePage === 'blub'}
class:bg-gray-100={activePage === 'blub'}
class="flex items-center justify-between px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
role="button"
on:click={() => {
dropdown1 = !dropdown1;
}}>
<div class="flex items-center">
<svg
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor">
<path
fill-rule="evenodd"
d="M12.316 3.051a1 1 0 01.633 1.265l-4 12a1 1 0 11-1.898-.632l4-12a1 1 0 011.265-.633zM5.707 6.293a1 1 0 010 1.414L3.414 10l2.293 2.293a1 1 0 11-1.414 1.414l-3-3a1 1 0 010-1.414l3-3a1 1 0 011.414 0zm8.586 0a1 1 0 011.414 0l3 3a1 1 0 010 1.414l-3 3a1 1 0 11-1.414-1.414L16.586 10l-2.293-2.293a1 1 0 010-1.414z"
clip-rule="evenodd" />
</svg>
<span>Integrations</span>
</div>
{#if dropdown1}
<svg
class="flex-shrink-0 w-4 h-4 ml-2 transition transform"
xmlns="http://www.w3.org/2000/svg"
style="transform:rotate(90deg)"
viewBox="0 0 20 20"
fill="currentColor">
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd" />
</svg>
{:else}
<svg
class="flex-shrink-0 w-4 h-4 ml-2 transition transform"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor">
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd" />
</svg>
{/if}
</div>
{#if dropdown1}
<div class="mb-4">
<a
class="flex items-center py-2 pl-12 pr-4 transition cursor-pointer hover:bg-gray-100 hover:text-gray-900"
href="#">Shopify</a>
<a
class="flex items-center py-2 pl-12 pr-4 transition cursor-pointer hover:bg-gray-100 hover:text-gray-900"
href="#">Slack</a>
<a
class="flex items-center py-2 pl-12 pr-4 transition cursor-pointer hover:bg-gray-100 hover:text-gray-900"
href="#">Zapier</a>
</div>
{/if}
</div>
<a
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
href="#">
<svg
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor">
<path
fill-rule="evenodd"
d="M5 5a3 3 0 015-2.236A3 3 0 0114.83 6H16a2 2 0 110 4h-5V9a1 1 0 10-2 0v1H4a2 2 0 110-4h1.17C5.06 5.687 5 5.35 5 5zm4 1V5a1 1 0 10-1 1h1zm3 0a1 1 0 10-1-1v1h1z"
clip-rule="evenodd" />
<path d="M9 11H3v5a2 2 0 002 2h4v-7zM11 18h4a2 2 0 002-2v-5h-6v7z" />
</svg>
<span>{$_('changelog')}</span>
</a>
<a
class:dark:bg-gray-900={$router.path === '/settings/'}
class:bg-gray-100={$router.path === '/settings/'}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
href="/settings/">
<svg
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor">
<path
fill-rule="evenodd"
d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z"
clip-rule="evenodd" />
</svg>
<span>{$_('settings')}</span>
</a>
<a
class:dark:bg-gray-900={$router.path === '/about/'}
class:bg-gray-100={$router.path === '/about/'}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
href="/about/">
<svg
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
xmlns="http://www.w3.org/2000/svg"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" />
<path d="M12 16v-4M12 8h.01" /></svg>
<span>{$_('about')}</span>
</a>
<span
tabindex="0"
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
on:click={() => {
AuthService.authControllerLogout();
logout();
}}>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z" />
<path
d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2a9.985 9.985 0 0 1 8 4h-2.71a8 8 0 1 0 .001 12h2.71A9.985 9.985 0 0 1 12 22zm7-6v-3h-8v-2h8V8l5 4-5 4z" /></svg>
<span>{$_('logout')}</span>
</span>
</nav>
</nav>
<div class="ml-0 transition md:ml-60">
<header
class="flex items-center justify-between w-full px-4 border-b h-14">
<button
on:click={() => {
navOpen = !navOpen;
}}
class="block btn btn-light md:hidden">
<span class="sr-only">Menu</span>
<svg
class="w-4 h-4"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor">
<path
fill-rule="evenodd"
d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
clip-rule="evenodd" />
</svg>
</button>
<!-- <div class="hidden -ml-3 form-icon md:block w-96">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<input
class="border-0 form-input"
placeholder="Search for articles..." />
</div> -->
<div class="flex items-end">
<a href="#" class="flex text-gray-500">
<svg
class="flex-shrink-0 w-5 h-5"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor">
<path
d="M10 2a6 6 0 00-6 6v3.586l-.707.707A1 1 0 004 14h12a1 1 0 00.707-1.707L16 11.586V8a6 6 0 00-6-6zM10 18a3 3 0 01-3-3h6a3 3 0 01-3 3z" />
</svg>
</a>
<a href="/profile/" class="ml-4">
<img
class="h-8 w-8 rounded-full"
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
alt="Profile Picture" />
</a>
</div>
</header>
<slot>
<NoComponentLoaded />
</slot>
</div>
<!-- Sidebar Backdrop -->
<div
on:click={() => {
navOpen = false;
}}
class:hidden={!navOpen}
class="fixed inset-0 z-10 w-screen h-screen bg-black bg-opacity-25 md:hidden" />
</section>
-31
View File
@@ -1,31 +0,0 @@
<script>
import { _, json } from "svelte-i18n";
import { getlang } from "./datatable_i18n";
import { Grid } from "gridjs";
import "gridjs/dist/theme/mermaid.css";
//
let table;
const datatable = new Grid({
columns: ["Name", "Email", "Phone Number"],
language: getlang($json("datatable")),
sort: true,
search: { enabled: true },
data: [
["John", "john@example.com", "(353) 01 222 3333"],
["Mark", "mark@gmail.com", "(01) 22 888 4444"],
["Eoin", "eoin@gmail.com", "0097 22 654 00033"],
["Sarah", "sarahcdd@gmail.com", "+322 876 1233"],
["Afshin", "afshin@mail.com", "(353) 22 87 8356"],
],
pagination: {
enabled: true,
limit: 2,
summary: false,
},
});
setTimeout(() => {
datatable.render(table);
}, 0);
</script>
<div bind:this={table} />
-74
View File
@@ -1,74 +0,0 @@
<script>
import "filepond/dist/filepond.css";
import FilePond from "svelte-filepond";
import { _ } from "svelte-i18n";
let pond;
// pond.getFiles() will return the active files
// the name to use for the internal file input
let name = "filepond";
function handleInit() {
// console.log("FilePond has initialised");
}
function handleAddFile(err, fileItem) {
// console.log("A file has been added", fileItem);
}
const labelInvalidField = $_("filepond__field-contains-invalid-files");
const labelFileWaitingForSize = $_("filepond__waiting-for-size");
const labelFileSizeNotAvailable = $_("filepond__size-not-available");
const labelFileLoading = $_("filepond__loading");
const labelFileLoadError = $_("filepond__error-during-load");
const labelFileProcessing = $_("filepond__uploading");
const labelFileProcessingComplete = $_("filepond__upload-complete");
const labelFileProcessingAborted = $_("filepond__upload-cancelled");
const labelFileProcessingError = $_("filepond__error-during-upload");
const labelFileProcessingRevertError = $_("filepond__error-during-revert");
const labelFileRemoveError = $_("filepond__error-during-remove");
const labelTapToCancel = $_("filepond__tap-to-cancel");
const labelTapToRetry = $_("filepond__tap-to-retry");
const labelTapToUndo = $_("filepond__tap-to-undo");
const labelButtonRemoveItem = $_("filepond__remove");
const labelButtonAbortItemLoad = $_("filepond__abort");
const labelButtonRetryItemLoad = $_("filepond__retry");
const labelButtonAbortItemProcessing = $_("filepond__cancel");
const labelButtonUndoItemProcessing = $_("filepond__undo");
const labelButtonRetryItemProcessing = $_("filepond__retry");
const labelButtonProcessItem = $_("filepond__upload");
const labelIdle =
$_("drag-and-drop-your-files-or") +
` <span class="filepond--label-action"> ` +
$_("browse") +
` </span>`;
</script>
<div class="app">
<FilePond
bind:this={pond}
{name}
{labelFileWaitingForSize}
{labelFileSizeNotAvailable}
{labelFileLoading}
{labelFileLoadError}
{labelFileProcessing}
{labelFileProcessingComplete}
{labelFileProcessingAborted}
{labelFileProcessingError}
{labelFileProcessingRevertError}
{labelFileRemoveError}
{labelTapToCancel}
{labelTapToRetry}
{labelTapToUndo}
{labelButtonRemoveItem}
{labelButtonAbortItemLoad}
{labelButtonRetryItemLoad}
{labelButtonAbortItemProcessing}
{labelButtonUndoItemProcessing}
{labelButtonRetryItemProcessing}
{labelButtonProcessItem}
{labelIdle}
{labelInvalidField}
server="/api"
allowMultiple={false}
credits={false}
oninit={handleInit}
onaddfile={handleAddFile} />
</div>
-274
View File
@@ -1,274 +0,0 @@
<!--
This example requires Tailwind CSS v2.0+
This example requires some changes to your config:
```
// tailwind.config.js
module.exports = {
// ...
plugins: [
// ...
require('@tailwindcss/forms'),
]
}
```
-->
<div>
<div class="md:grid md:grid-cols-3 md:gap-6">
<div class="md:col-span-1">
<div class="px-4 sm:px-0">
<h3 class="text-lg font-medium leading-6 text-gray-900">Profile</h3>
<p class="mt-1 text-sm text-gray-600">
This information will be displayed publicly so be careful what you share.
</p>
</div>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<form action="#" method="POST">
<div class="shadow sm:rounded-md sm:overflow-hidden">
<div class="px-4 py-5 bg-white space-y-6 sm:p-6">
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="company_website" class="block text-sm font-medium text-gray-700">
Website
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<span class="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 text-sm">
http://
</span>
<input type="text" name="company_website" id="company_website" class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border-gray-300" placeholder="www.example.com">
</div>
</div>
</div>
<div>
<label for="about" class="block text-sm font-medium text-gray-700">
About
</label>
<div class="mt-1">
<textarea id="about" name="about" rows="3" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 mt-1 block w-full sm:text-sm border-gray-300 rounded-md" placeholder="you@example.com"></textarea>
</div>
<p class="mt-2 text-sm text-gray-500">
Brief description for your profile. URLs are hyperlinked.
</p>
</div>
<div>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="block text-sm font-medium text-gray-700">
Photo
</label>
<div class="mt-2 flex items-center">
<span class="inline-block h-12 w-12 rounded-full overflow-hidden bg-gray-100">
<svg class="h-full w-full text-gray-300" fill="currentColor" viewBox="0 0 24 24">
<path d="M24 20.993V24H0v-2.996A14.977 14.977 0 0112.004 15c4.904 0 9.26 2.354 11.996 5.993zM16.002 8.999a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
</span>
<button type="button" class="ml-5 bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Change
</button>
</div>
</div>
<div>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="block text-sm font-medium text-gray-700">
Cover photo
</label>
<div class="mt-2 flex justify-center px-6 pt-5 pb-6 border-2 border-gray-300 border-dashed rounded-md">
<div class="space-y-1 text-center">
<svg class="mx-auto h-12 w-12 text-gray-400" stroke="currentColor" fill="none" viewBox="0 0 48 48" aria-hidden="true">
<path d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</svg>
<div class="flex text-sm text-gray-600">
<label for="file-upload" class="relative cursor-pointer bg-white rounded-md font-medium text-indigo-600 hover:text-indigo-500 focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-indigo-500">
<span>Upload a file</span>
<input id="file-upload" name="file-upload" type="file" class="sr-only">
</label>
<p class="pl-1">or drag and drop</p>
</div>
<p class="text-xs text-gray-500">
PNG, JPG, GIF up to 10MB
</p>
</div>
</div>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Save
</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="hidden sm:block" aria-hidden="true">
<div class="py-5">
<div class="border-t border-gray-200"></div>
</div>
</div>
<div class="mt-10 sm:mt-0">
<div class="md:grid md:grid-cols-3 md:gap-6">
<div class="md:col-span-1">
<div class="px-4 sm:px-0">
<h3 class="text-lg font-medium leading-6 text-gray-900">Personal Information</h3>
<p class="mt-1 text-sm text-gray-600">
Use a permanent address where you can receive mail.
</p>
</div>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<form action="#" method="POST">
<div class="shadow overflow-hidden sm:rounded-md">
<div class="px-4 py-5 bg-white sm:p-6">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<label for="first_name" class="block text-sm font-medium text-gray-700">First name</label>
<input type="text" name="first_name" id="first_name" autocomplete="given-name" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
</div>
<div class="col-span-6 sm:col-span-3">
<label for="last_name" class="block text-sm font-medium text-gray-700">Last name</label>
<input type="text" name="last_name" id="last_name" autocomplete="family-name" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
</div>
<div class="col-span-6 sm:col-span-4">
<label for="email_address" class="block text-sm font-medium text-gray-700">Email address</label>
<input type="text" name="email_address" id="email_address" autocomplete="email" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
</div>
<div class="col-span-6 sm:col-span-3">
<label for="country" class="block text-sm font-medium text-gray-700">Country / Region</label>
<select id="country" name="country" autocomplete="country" class="mt-1 block w-full py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<option>United States</option>
<option>Canada</option>
<option>Mexico</option>
</select>
</div>
<div class="col-span-6">
<label for="street_address" class="block text-sm font-medium text-gray-700">Street address</label>
<input type="text" name="street_address" id="street_address" autocomplete="street-address" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
</div>
<div class="col-span-6 sm:col-span-6 lg:col-span-2">
<label for="city" class="block text-sm font-medium text-gray-700">City</label>
<input type="text" name="city" id="city" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
</div>
<div class="col-span-6 sm:col-span-3 lg:col-span-2">
<label for="state" class="block text-sm font-medium text-gray-700">State / Province</label>
<input type="text" name="state" id="state" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
</div>
<div class="col-span-6 sm:col-span-3 lg:col-span-2">
<label for="postal_code" class="block text-sm font-medium text-gray-700">ZIP / Postal</label>
<input type="text" name="postal_code" id="postal_code" autocomplete="postal-code" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md">
</div>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Save
</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="hidden sm:block" aria-hidden="true">
<div class="py-5">
<div class="border-t border-gray-200"></div>
</div>
</div>
<div class="mt-10 sm:mt-0">
<div class="md:grid md:grid-cols-3 md:gap-6">
<div class="md:col-span-1">
<div class="px-4 sm:px-0">
<h3 class="text-lg font-medium leading-6 text-gray-900">Notifications</h3>
<p class="mt-1 text-sm text-gray-600">
Decide which communications you'd like to receive and how.
</p>
</div>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<form action="#" method="POST">
<div class="shadow overflow-hidden sm:rounded-md">
<div class="px-4 py-5 bg-white space-y-6 sm:p-6">
<fieldset>
<legend class="text-base font-medium text-gray-900">By Email</legend>
<div class="mt-4 space-y-4">
<div class="flex items-start">
<div class="flex items-center h-5">
<input id="comments" name="comments" type="checkbox" class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded">
</div>
<div class="ml-3 text-sm">
<label for="comments" class="font-medium text-gray-700">Comments</label>
<p class="text-gray-500">Get notified when someones posts a comment on a posting.</p>
</div>
</div>
<div class="flex items-start">
<div class="flex items-center h-5">
<input id="candidates" name="candidates" type="checkbox" class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded">
</div>
<div class="ml-3 text-sm">
<label for="candidates" class="font-medium text-gray-700">Candidates</label>
<p class="text-gray-500">Get notified when a candidate applies for a job.</p>
</div>
</div>
<div class="flex items-start">
<div class="flex items-center h-5">
<input id="offers" name="offers" type="checkbox" class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded">
</div>
<div class="ml-3 text-sm">
<label for="offers" class="font-medium text-gray-700">Offers</label>
<p class="text-gray-500">Get notified when a candidate accepts or rejects an offer.</p>
</div>
</div>
</div>
</fieldset>
<fieldset>
<div>
<legend class="text-base font-medium text-gray-900">Push Notifications</legend>
<p class="text-sm text-gray-500">These are delivered via SMS to your mobile phone.</p>
</div>
<div class="mt-4 space-y-4">
<div class="flex items-center">
<input id="push_everything" name="push_notifications" type="radio" class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300">
<label for="push_everything" class="ml-3 block text-sm font-medium text-gray-700">
Everything
</label>
</div>
<div class="flex items-center">
<input id="push_email" name="push_notifications" type="radio" class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300">
<label for="push_email" class="ml-3 block text-sm font-medium text-gray-700">
Same as email
</label>
</div>
<div class="flex items-center">
<input id="push_nothing" name="push_notifications" type="radio" class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300">
<label for="push_nothing" class="ml-3 block text-sm font-medium text-gray-700">
No push notifications
</label>
</div>
</div>
</fieldset>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Save
</button>
</div>
</div>
</form>
</div>
</div>
</div>
-97
View File
@@ -1,97 +0,0 @@
<script>
import store from "../store.js";
store.init();
const login = () => {
store.login();
};
</script>
<div
class="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
<div class="max-w-md w-full space-y-8">
<div>
<img
class="mx-auto h-12 w-auto"
src="/lfk-logo.png"
alt="" />
<h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900">
Sign in to your account
</h2>
<p class="mt-2 text-center text-sm text-gray-600">
Or
<a href="#" class="font-medium text-indigo-600 hover:text-indigo-500">
start your 14-day free trial
</a>
</p>
</div>
<div>
<input type="hidden" name="remember" value="true" />
<div class="rounded-md shadow-sm -space-y-px">
<div>
<label for="email-address" class="sr-only">Email address</label>
<input
id="email-address"
name="email"
type="email"
autocomplete="email"
required
class="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm"
placeholder="Email address" />
</div>
<div>
<label for="password" class="sr-only">Password</label>
<input
id="password"
name="password"
type="password"
autocomplete="current-password"
required
class="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm"
placeholder="Password" />
</div>
</div>
<div class="flex items-center justify-between">
<div class="flex items-center">
<input
id="remember_me"
name="remember_me"
type="checkbox"
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded" />
<label for="remember_me" class="ml-2 block text-sm text-gray-900">
Remember me
</label>
</div>
<div class="text-sm">
<a href="#" class="font-medium text-indigo-600 hover:text-indigo-500">
Forgot your password?
</a>
</div>
</div>
<div>
<button
on:click="{login}"
type="submit"
class="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
<span class="absolute left-0 inset-y-0 flex items-center pl-3">
<!-- Heroicon name: lock-closed -->
<svg
class="h-5 w-5 text-indigo-500 group-hover:text-indigo-400"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true">
<path
fill-rule="evenodd"
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
clip-rule="evenodd" />
</svg>
</span>
Sign in
</button>
</div>
</div>
</div>
</div>
-25
View File
@@ -1,25 +0,0 @@
<script>
import { _ } from "svelte-i18n";
import StatCards from "./StatCards.svelte";
import store from "../store";
import ComponentDump from "./ComponentDump.svelte";
let navOpen = false;
</script>
<div
class="p-5 overflow-x-hidden"
on:click={() => {
navOpen = false;
}}>
<!-- <div class="border-4 border-dashed rounded h-96" /> -->
<h1 class="text-3xl leading-tight">
<span class="font-extrabold">{$_('dashboard-title')}</span> <span>
-
{$_('dashboard-greeting')},
<span
class="text-blue-500">{store.state.jwtinfo.userdetails.firstname}</span>
👋</span>
</h1>
<StatCards />
<ComponentDump />
</div>
-83
View File
@@ -1,83 +0,0 @@
<script>
export let params;
</script>
<section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight">
Orgs
</span>
<p class="mb-8 text-lg text-gray-500">
configure the tracks & minimum lap times
</p>
<div class="flex flex-row mb-4">
<div class="w-full">
<nav class="w-full flex">
<ol class="list-none flex flex-row items-center justify-start">
<li class="mr-2 flex items-center">
<svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="h-3 w-3 stroke-current"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"><path
d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
<polyline points="9 22 9 12 15 12 15 22" /></svg>
</li>
<li class="flex items-center">
<a class="mr-2" href="/">Home</a><svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="h-3 w-3 mr-2 stroke-current"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"><line
x1="5"
y1="12"
x2="19"
y2="12" />
<polyline points="12 5 19 12 12 19" /></svg>
</li>
<li class="mr-2 flex items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"><path fill="none" d="M0 0h24v24H0z" />
<path
d="M21 20h2v2H1v-2h2V3a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v17zm-2 0V4H5v16h14zM8 11h3v2H8v-2zm0-4h3v2H8V7zm0 8h3v2H8v-2zm5 0h3v2h-3v-2zm0-4h3v2h-3v-2zm0-4h3v2h-3V7z" /></svg>
</li>
<li class="flex items-center">
<a class="mr-2" href="./">Orgs</a><svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="h-3 w-3 mr-2 stroke-current"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"><line
x1="5"
y1="12"
x2="19"
y2="12" />
<polyline points="12 5 19 12 12 19" /></svg>
</li>
<li class="flex items-center">
<span class="mr-2">Org-Details #{params.orgid}</span>
</li>
</ol>
</nav>
</div>
</div>
</section>
-13
View File
@@ -1,13 +0,0 @@
<script>
import { _ } from "svelte-i18n";
</script>
<section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight">
Orgs
</span>
<p class="mb-8 text-lg text-gray-500">
add, delete, edit organizations
</p>
<nav><a class="underline" href="./1">Org 1</a></nav>
</section>
-10
View File
@@ -1,10 +0,0 @@
<script>
import { _ } from "svelte-i18n";
</script>
<section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight">
{$_('runners')}
</span>
<p class="mb-8 text-lg text-gray-500">läuft bei ihnen</p>
</section>
-35
View File
@@ -1,35 +0,0 @@
<script>
import { _ } from "svelte-i18n";
import FormLayout from "./FormLayout.svelte";
</script>
<div class="pt-12 px-4 sm:px-6 lg:px-8 lg:pt-20 bg-gray-900 pb-12">
<div class="text-center mb-8">
<h1
class="mt-9 font-display text-4xl leading-none font-semibold text-white sm:text-5xl lg:text-6xl">
🔨<br />{$_('settings')}
</h1>
<p
class="mt-2 max-w-xl mx-auto text-xl lg:max-w-3xl lg:text-2xl text-gray-300">
<span class="text-lg">configure your profile however you want</span>
</p>
</div>
</div>
<div class="pt-0 pb-16 bg-gray-50 overflow-hidden lg:pt-12 lg:py-24">
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
<!-- <h2 class="text-4xl font-display font-semibold text-gray-900 md:text-5xl">
General
</h2> -->
<div
class="max-w-3xl mx-auto text-xl leading-8 font-medium text-gray-900 mb-16">
<p class="text-center">
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Temporibus et
amet voluptate nulla accusantium vero blanditiis nobis facere veritatis.
Impedit deserunt saepe aliquid unde consequuntur officia consequatur
fugit iusto dolorem?
</p>
</div>
<FormLayout />
</div>
</div>
-165
View File
@@ -1,165 +0,0 @@
<script>
import { StatsService } from "@odit/lfk-client-js";
import { _ } from "svelte-i18n";
const stats_promise = StatsService.statsControllerGet();
</script>
<!-- -->
<h1>{$_('general-stats')}</h1>
{#await stats_promise}
<div
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
role="alert">
<p class="font-bold">{$_('stats-are-being-loaded')}</p>
<p class="text-sm">{$_('this-might-take-a-moment')}</p>
</div>
{:then stats}
<div
class="flex flex-col lg:flex-row w-full lg:space-x-2 space-y-2 lg:space-y-0 mb-2 lg:mb-4">
<a href="/runners/" class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890 dark:bg-gray-900 dark:text-white">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">
{$_('runners')}
</div>
<div class="text-xl font-bold">{stats.total_runners}</div>
</div>
<svg
height="24"
width="24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none" />
<path
d="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1 2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1l-5.2 2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" /></svg>
</div>
</div>
</a>
<div class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890 dark:bg-gray-900 dark:text-white">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">
{$_('total-scans')}
</div>
<div class="text-xl font-bold">{stats.total_scans}</div>
</div><svg
stroke="currentColor"
fill="currentColor"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
size="24"
class="stroke-current text-grey-500"
height="24"
width="24"
xmlns="http://www.w3.org/2000/svg"><polyline
points="22 12 18 12 15 21 9 3 6 12 2 12" /></svg>
</div>
</div>
</div>
<div class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890 dark:bg-gray-900 dark:text-white">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">
{$_('total-donations')}
</div>
<div class="text-xl font-bold">{stats.total_donation}</div>
</div><svg
xmlns="http://www.w3.org/2000/svg"
height="24"
fill="currentColor"
width="24"><path d="M0 0h24v24H0z" fill="none" />
<path
d="M15 18.5A6.48 6.48 0 019.24 15H15v-2H8.58c-.05-.33-.08-.66-.08-1s.03-.67.08-1H15V9H9.24A6.491 6.491 0 0115 5.5c1.61 0 3.09.59 4.23 1.57L21 5.3A8.955 8.955 0 0015 3c-3.92 0-7.24 2.51-8.48 6H3v2h3.06a8.262 8.262 0 000 2H3v2h3.52c1.24 3.49 4.56 6 8.48 6 2.31 0 4.41-.87 6-2.3l-1.78-1.77c-1.13.98-2.6 1.57-4.22 1.57z" /></svg>
</div>
</div>
</div>
<div class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890 dark:bg-gray-900 dark:text-white">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">
{$_('total-distance')}
</div>
<div class="text-xl font-bold">
{stats.total_distance / 1000}
km
</div>
</div>
<svg
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
height="24"
width="24"><path d="M0 0h24v24H0z" fill="none" />
<path
d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 10H3V8h2v4h2V8h2v4h2V8h2v4h2V8h2v4h2V8h2v8z" /></svg>
</div>
</div>
</div>
<a href="/teams/" class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890 dark:bg-gray-900 dark:text-white">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">
{$_('count_teams')}
</div>
<div class="text-xl font-bold">{stats.total_teams}</div>
</div>
<svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
size="24"
class="stroke-current text-grey-500"
height="24"
width="24"
xmlns="http://www.w3.org/2000/svg"><path
d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
<circle cx="9" cy="7" r="4" />
<path d="M23 21v-2a4 4 0 0 0-3-3.87" />
<path d="M16 3.13a4 4 0 0 1 0 7.75" /></svg>
</div>
</div>
</a>
<a href="/orgs/" class="w-full lg:w-1/4">
<div
class="widget w-full p-4 rounded-lg bg-white border border-grey-100 dark:bg-grey-895 dark:border-grey-890 dark:bg-gray-900 dark:text-white">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-xs uppercase font-light text-grey-500">
{$_('count_organizations')}
</div>
<div class="text-xl font-bold">{stats.total_orgs}</div>
</div>
<svg
height="24"
fill="currentColor"
width="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z" />
<path
d="M17 11V3H7v4H3v14h8v-4h2v4h8V11h-4zM7 19H5v-2h2v2zm0-4H5v-2h2v2zm0-4H5V9h2v2zm4 4H9v-2h2v2zm0-4H9V9h2v2zm0-4H9V5h2v2zm4 8h-2v-2h2v2zm0-4h-2V9h2v2zm0-4h-2V5h2v2zm4 12h-2v-2h2v2zm0-4h-2v-2h2v2z" /></svg>
</div>
</div>
</a>
</div>
{:catch error}
<div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500">
<span class="inline-block align-middle mr-8">
<b class="capitalize">{$_('general_promise_error')}</b>
{error}
</span>
</div>
{/await}
-10
View File
@@ -1,10 +0,0 @@
<script>
import { _ } from "svelte-i18n";
</script>
<section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight">
{$_('teams')}
</span>
<p class="mb-8 text-lg text-gray-500">everything is more fun together 🏃‍♂️🏃‍♀️🏃‍♂️</p>
</section>
-5
View File
@@ -1,5 +0,0 @@
<script>
import { _, locale } from "svelte-i18n";
</script>
<div>$locale $_('hallo')</div>
-189
View File
@@ -1,189 +0,0 @@
<script>
import { _, json } from "svelte-i18n";
import Toastify from "toastify-js";
import TracksEmptyState from "./TracksEmptyState.svelte";
import { TrackService } from "@odit/lfk-client-js";
const tracks_promise = TrackService.trackControllerGetAll();
import { getlang } from "./datatable_i18n";
import { Grid, html } from "gridjs";
import "gridjs/dist/theme/mermaid.css";
import { tracks as tracksstore } from "../store.js";
$: trackscache = [];
$: blocked = [];
let table;
let datatable;
let datatable_inited = false;
tracksstore.subscribe((val) => {
trackscache = val;
setTimeout(() => {
if (val.length > 0) {
renderdatatable();
}
}, 100);
});
tracks_promise.then((data) => {
tracksstore.set(data);
});
window.track__edit_cancel = () => renderdatatable();
window.track__edit_save = () => {
const trackid = parseInt(window.event.target.getAttribute("data-trackid"));
if (blocked.includes(trackid)) {
//
} else {
blocked.push(trackid);
const elem = document.querySelector(
`[data-id="triggered_table_actions_${trackid}"]`
).parentNode.parentNode.parentNode;
Toastify({
text: "Track is being updated...",
duration: 500,
}).showToast();
TrackService.trackControllerPut(trackid, {
id: trackid,
name: elem.childNodes[0].childNodes[0].value,
distance: parseInt(elem.childNodes[1].childNodes[0].value),
minimumLapTime: parseInt(elem.childNodes[2].childNodes[0].value),
})
.then((r) => {
Toastify({
text: "Track was updated!",
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
duration: 1000,
}).showToast();
blocked = blocked.filter((e) => e !== trackid);
document
.querySelector(`[data-id="default_table_actions_${trackid}"]`)
.classList.remove("hidden");
document
.querySelector(`[data-id="triggered_table_actions_${trackid}"]`)
.classList.add("hidden");
//
elem.childNodes[0].innerHTML = `<td data-column-id="trackName" class="gridjs-td">${elem.childNodes[0].childNodes[0].value}</td>`;
elem.childNodes[1].innerHTML = `<td data-column-id="trackName" class="gridjs-td">${elem.childNodes[1].childNodes[0].value}</td>`;
elem.childNodes[2].innerHTML = `<td data-column-id="trackName" class="gridjs-td">${elem.childNodes[2].childNodes[0].value}</td>`;
})
.catch((err) => {
console.error(err);
});
}
};
window.track__delete_handler = () => {
const trackid = parseInt(window.event.target.getAttribute("data-trackid"));
document
.querySelector(`[data-id="default_table_actions_${trackid}"]`)
.classList.add("hidden");
document
.querySelector(`[data-id="deleteconfirmation_table_actions_${trackid}"]`)
.classList.remove("hidden");
};
window.track__delete_cancel = () => {
const trackid = parseInt(window.event.target.getAttribute("data-trackid"));
document
.querySelector(`[data-id="default_table_actions_${trackid}"]`)
.classList.remove("hidden");
document
.querySelector(`[data-id="deleteconfirmation_table_actions_${trackid}"]`)
.classList.add("hidden");
};
window.track__delete_confirm = () => {
const trackid = parseInt(window.event.target.getAttribute("data-trackid"));
TrackService.trackControllerRemove(trackid)
.then(() => {
const newStoreVal = trackscache.filter((obj) => obj.id !== trackid);
tracksstore.set(newStoreVal);
renderdatatable();
})
.catch((err) => {
console.log(err);
});
};
window.track__edit_handler = () => {
const trackid = parseInt(window.event.target.getAttribute("data-trackid"));
document
.querySelector(`[data-id="default_table_actions_${trackid}"]`)
.classList.add("hidden");
document
.querySelector(`[data-id="triggered_table_actions_${trackid}"]`)
.classList.remove("hidden");
const elem = document.querySelector(
`[data-id="triggered_table_actions_${trackid}"]`
).parentNode.parentNode.parentNode;
const trackname = elem.childNodes[0].textContent;
const tracklength = parseInt(elem.childNodes[1].textContent);
const trackmintime = parseInt(elem.childNodes[2].textContent);
elem.childNodes[0].innerHTML = `<input type="text" value="${trackname}" name="trackname" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2">`;
elem.childNodes[1].innerHTML = `<input type="text" value="${tracklength}" name="tracklength" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2">`;
elem.childNodes[2].innerHTML = `<input type="text" value="${trackmintime}" name="trackmintime" class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2">`;
};
//
function renderdatatable() {
let tabledata = [];
trackscache.forEach((track) => {
tabledata.push([
track.name,
track.distance,
track.minimumLapTime || 0,
html(`
<div class="hidden" data-id="triggered_table_actions_${track.id}">
<button class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-green-400 text-base font-medium text-white sm:w-auto sm:text-sm" data-trackid="${track.id}" onclick="track__edit_save()">Save</button>
<button class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-500 text-base font-medium text-white sm:w-auto sm:text-sm" data-trackid="${track.id}" onclick="track__edit_cancel()">Cancel</button>
</div>
<div data-id="default_table_actions_${track.id}">
<button class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-400 text-base font-medium text-white sm:w-auto sm:text-sm" data-trackid="${track.id}" onclick="track__edit_handler()">Edit</button>
<button class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-500 text-base font-medium text-white sm:w-auto sm:text-sm" data-trackid="${track.id}" onclick="track__delete_handler()">Delete</button>
</div>
<div class="hidden" data-id="deleteconfirmation_table_actions_${track.id}">
<button class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-400 text-base font-medium text-white sm:w-auto sm:text-sm" data-trackid="${track.id}" onclick="track__delete_cancel()">Cancel</button>
<button class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-500 text-base font-medium text-white sm:w-auto sm:text-sm" data-trackid="${track.id}" onclick="track__delete_confirm()">Confirm</button>
</div>
`),
]);
});
if (datatable_inited === false) {
datatable = new Grid({
columns: [
$_("track-name"),
$_("track-length-in-m"),
$_("minimum-lap-time-in-s"),
$_("action"),
],
language: getlang($json("datatable")),
sort: true,
search: { enabled: true },
data: tabledata,
pagination: {
enabled: true,
limit: 25,
summary: false,
},
}).render(table);
datatable_inited = true;
} else {
datatable.updateConfig({ data: tabledata }).forceRender();
}
}
</script>
{#if trackscache.length > 0}
<div bind:this={table} />
{/if}
{#await tracks_promise}
<div
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
role="alert">
<p class="font-bold">{$_('track-data-is-being-loaded')}</p>
<p class="text-sm">{$_('this-might-take-a-moment')}</p>
</div>
{:then}
{#if trackscache.length === 0}
<TracksEmptyState />
{/if}
{:catch error}
<div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500">
<span class="inline-block align-middle mr-8">
<b class="capitalize">{$_('general_promise_error')}</b>
{error}
</span>
</div>
{/await}
-25
View File
@@ -1,25 +0,0 @@
<script>
import { _ } from "svelte-i18n";
import AddTrackModal from "./AddTrackModal.svelte";
let modal_open = false;
import Tracks from "./Tracks.svelte";
</script>
<section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight">
Tracks
<button
on:click={() => {
modal_open = true;
}}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
Create Track
</button>
</span>
<p class="mb-8 text-lg text-gray-500">
configure the tracks & minimum lap times
</p>
<Tracks />
</section>
<AddTrackModal bind:modal_open />
-335
View File
@@ -1,335 +0,0 @@
<script>
import { _ } from "svelte-i18n";
import lodashIsEqual from "lodash.isequal";
import store from "../store";
import {
UserService,
UserGroupService,
PermissionService,
} from "@odit/lfk-client-js";
import "gridjs/dist/theme/mermaid.css";
import Toastify from "toastify-js";
import PromiseError from "./PromiseError.svelte";
export let params;
const user_promise = UserService.userControllerGetOne(params.userid);
let data_loaded = false;
$: delete_triggered = false;
$: original_data = {};
$: editable_userdata = {};
$: allpermissions = [];
$: allgroups = [];
$: allgroups_ids = [];
$: usergroups_array_objects = [];
$: usergroups_array = [];
let usergroups_array_original = [];
user_promise.then((data) => {
data_loaded = true;
original_data = Object.assign(original_data, data);
editable_userdata = data;
data.groups.forEach((g) => {
usergroups_array=usergroups_array.concat([g.id]);
});
usergroups_array_original = usergroups_array;
allgroups.forEach((g) => {
allgroups_ids.push(g.id);
});
});
UserGroupService.userGroupControllerGetAll().then((data) => {
allgroups = data;
});
const permissions_promise = PermissionService.permissionControllerGetAll();
permissions_promise.then((data) => {
data.forEach((p) => {
allpermissions=allpermissions.concat([p.target + ":" + p.action])
});
});
$: changes_performed = !lodashIsEqual(original_data, editable_userdata);
$: groups_changed = JSON.stringify(usergroups_array)===JSON.stringify(usergroups_array_original);
$: save_enabled = changes_performed||!groups_changed;
function submit() {
if (
!lodashIsEqual(original_data.permissions, editable_userdata.permissions)
) {
// TODO: add+delete permissions
}
if (data_loaded === true && save_enabled) {
let tmp=[];
usergroups_array.forEach(g => {
const group=allgroups.find(obj=>obj.id===g);
tmp.push(group);
});
editable_userdata.groups=tmp;
Toastify({
text: $_("updating-user"),
duration: 2500,
}).showToast();
UserService.userControllerPut(original_data.id, editable_userdata)
.then((resp) => {
Object.assign(original_data, editable_userdata);
original_data = editable_userdata;
Object.assign(original_data, editable_userdata);
//
Toastify({
text: $_("user-updated"),
duration: 2500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
})
.catch((err) => {
});
} else {
}
}
function deleteUser() {
UserService.userControllerRemove(original_data.id, true)
.then((resp) => {
location.replace("./");
})
.catch((err) => {
});
}
</script>
{#await user_promise}
<!-- -->
{:then user}
<section class="container p-5 select-none">
<div class="flex flex-row mb-4">
<div class="w-full">
<nav class="w-full flex">
<ol class="list-none flex flex-row items-center justify-start">
<li class="flex items-center">
<svg
class="flex-shrink-0 w-5 h-5 mr-2"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 640 512"><path
fill="currentColor"
d="M610.5 341.3c2.6-14.1 2.6-28.5 0-42.6l25.8-14.9c3-1.7 4.3-5.2 3.3-8.5-6.7-21.6-18.2-41.2-33.2-57.4-2.3-2.5-6-3.1-9-1.4l-25.8 14.9c-10.9-9.3-23.4-16.5-36.9-21.3v-29.8c0-3.4-2.4-6.4-5.7-7.1-22.3-5-45-4.8-66.2 0-3.3.7-5.7 3.7-5.7 7.1v29.8c-13.5 4.8-26 12-36.9 21.3l-25.8-14.9c-2.9-1.7-6.7-1.1-9 1.4-15 16.2-26.5 35.8-33.2 57.4-1 3.3.4 6.8 3.3 8.5l25.8 14.9c-2.6 14.1-2.6 28.5 0 42.6l-25.8 14.9c-3 1.7-4.3 5.2-3.3 8.5 6.7 21.6 18.2 41.1 33.2 57.4 2.3 2.5 6 3.1 9 1.4l25.8-14.9c10.9 9.3 23.4 16.5 36.9 21.3v29.8c0 3.4 2.4 6.4 5.7 7.1 22.3 5 45 4.8 66.2 0 3.3-.7 5.7-3.7 5.7-7.1v-29.8c13.5-4.8 26-12 36.9-21.3l25.8 14.9c2.9 1.7 6.7 1.1 9-1.4 15-16.2 26.5-35.8 33.2-57.4 1-3.3-.4-6.8-3.3-8.5l-25.8-14.9zM496 368.5c-26.8 0-48.5-21.8-48.5-48.5s21.8-48.5 48.5-48.5 48.5 21.8 48.5 48.5-21.7 48.5-48.5 48.5zM96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm224 32c1.9 0 3.7-.5 5.6-.6 8.3-21.7 20.5-42.1 36.3-59.2 7.4-8 17.9-12.6 28.9-12.6 6.9 0 13.7 1.8 19.6 5.3l7.9 4.6c.8-.5 1.6-.9 2.4-1.4 7-14.6 11.2-30.8 11.2-48 0-61.9-50.1-112-112-112S208 82.1 208 144c0 61.9 50.1 112 112 112zm105.2 194.5c-2.3-1.2-4.6-2.6-6.8-3.9-8.2 4.8-15.3 9.8-27.5 9.8-10.9 0-21.4-4.6-28.9-12.6-18.3-19.8-32.3-43.9-40.2-69.6-10.7-34.5 24.9-49.7 25.8-50.3-.1-2.6-.1-5.2 0-7.8l-7.9-4.6c-3.8-2.2-7-5-9.8-8.1-3.3.2-6.5.6-9.8.6-24.6 0-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h255.4c-3.7-6-6.2-12.8-6.2-20.3v-9.2zM173.1 274.6C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg>
</li>
<li class="flex items-center">
<a class="mr-2" href="./">{$_('users')}</a><svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="h-3 w-3 mr-2 stroke-current"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"><line
x1="5"
y1="12"
x2="19"
y2="12" />
<polyline points="12 5 19 12 12 19" /></svg>
</li>
<li class="flex items-center">
<span class="mr-2">{original_data.firstname}
{original_data.middlename || ''}
{original_data.lastname}</span>
</li>
</ol>
</nav>
</div>
</div>
<div class="mb-8 text-3xl font-extrabold leading-tight">
{original_data.firstname}
{original_data.middlename || ''}
{original_data.lastname}
<span data-id="user_actions_${editable_userdata.id}">
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:DELETE')}
{#if delete_triggered}
<button
on:click={deleteUser}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('confirm-delete')}</button>
<button
on:click={() => {
delete_triggered = !delete_triggered;
}}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm">{$_('cancel')}</button>
{/if}
{#if !delete_triggered}
<button
on:click={() => {
delete_triggered = true;
}}
type="button"
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('delete-user')}</button>
{/if}
{/if}
{#if !delete_triggered}
<button
disabled={!save_enabled}
class:opacity-50={!save_enabled}
type="button"
on:click={submit}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('save-changes')}</button>
{/if}
</span>
</div>
<div class="mt-2 flex items-center">
<img
alt={$_('profile-picture')}
class="inline-block h-20 w-20 rounded-full overflow-hidden bg-gray-100"
src={editable_userdata.profilePic} />
<button
type="button"
class="ml-5 bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Change</button>
</div>
<!-- -->
<div class="mt-3 text-sm w-full">
<input
id="enabled"
on:change={() => {
editable_userdata.enabled = !editable_userdata.enabled;
// TODO: this reactive set does not work?
}}
name="enabled"
type="checkbox"
checked={editable_userdata.enabled}
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" />
<label
for="enabled"
class="ml-1 font-medium text-gray-700">Active?</label>
<p class="text-gray-500">set the user active/ inactive</p>
</div>
<div class="text-sm w-full">
<label
for="firstname"
class="font-medium text-gray-700">{$_('first-name')}</label>
<input
autocomplete="off"
placeholder={$_('first-name')}
type="text"
bind:value={editable_userdata.firstname}
name="firstname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
for="middlename"
class="font-medium text-gray-700">{$_('middle-name')}</label>
<input
autocomplete="off"
placeholder={$_('middle-name')}
type="text"
bind:value={editable_userdata.middlename}
name="middlename"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
for="lastname"
class="font-medium text-gray-700">{$_('last-name')}</label>
<input
autocomplete="off"
placeholder={$_('last-name')}
type="text"
bind:value={editable_userdata.lastname}
name="lastname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
for="email"
class="font-medium text-gray-700">{$_('e-mail-adress')}</label>
<input
autocomplete="off"
placeholder={$_('e-mail-adress')}
type="email"
bind:value={editable_userdata.email}
name="email"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<label
for="username"
class="font-medium text-gray-700">{$_('username')}</label>
<input
autocomplete="off"
placeholder={$_('username')}
type="text"
bind:value={editable_userdata.username}
name="username"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2" />
</div>
<div class="text-sm w-full">
<span class="font-medium">{$_('groups')}</span>
<!-- svelte-ignore a11y-no-onchange -->
<select
bind:value={usergroups_array}
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 dark:bg-gray-900 dark:text-gray-100 rounded-md p-2"
multiple>
{#each allgroups as g}
{#if usergroups_array.includes(g.id)}
<option selected value={g.id}>{g.name}</option>
{:else}
<option value={g.id}>{g.name}</option>
{/if}
{/each}
</select>
</div>
<div class="text-sm w-full">
<span class="font-medium">Permissions</span>
<div class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center">
<!-- -->
<div class="flex flex-wrap -mx-1 overflow-hidden">
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/2">
verfügbare
</div>
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/2">erteilte</div>
</div>
<!-- -->
<div class="flex flex-wrap -mx-1 overflow-hidden">
{#if allpermissions.length > 0}
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/2">
<div
class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center">
{#each allpermissions as p}
{#if !editable_userdata.permissions.includes(p)}
<p
class="block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 bg-gray-200 p-2 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input">
{p}
<button
on:click={() => {
editable_userdata.permissions.push(p);
editable_userdata.permissions = editable_userdata.permissions;
}}
type="button"
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-green-200 text-base font-medium text-black hover:bg-green-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 sm:ml-3 sm:w-auto sm:text-sm">+</button>
</p>
{/if}
{/each}
</div>
</div>
<div class="my-1 px-1 w-full overflow-hidden sm:w-1/2">
<div
class="border-4 border-dashed rounded mb-4 p-5 text-lg text-center">
{#each allpermissions as p}
{#if editable_userdata.permissions.includes(p)}
<p
class="block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 bg-gray-200 p-2 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input">
{p}
<button
on:click={() => {
editable_userdata.permissions = editable_userdata.permissions.filter((obj) => obj !== p);
}}
type="button"
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-300 text-base font-medium text-black hover:bg-red-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 sm:ml-3 sm:w-auto sm:text-sm">-</button>
</p>
{/if}
{/each}
</div>
</div>
{/if}
</div>
</div>
</div>
</section>
{:catch error}
<PromiseError {error} />
{/await}
-31
View File
@@ -1,31 +0,0 @@
<script>
import { _ } from "svelte-i18n";
import store from "../store";
import AddUserModal from "./AddUserModal.svelte";
export let modal_open = false;
import UsersOverview from "./UsersOverview.svelte";
console.log(store.state.jwtinfo.userdetails.permissions);
let current_users=[];
</script>
<section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight">
{$_('users')}
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')}
<button
on:click={() => {
modal_open = true;
}}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
{$_('create-user')}
</button>
{/if}
</span>
<p class="mb-8 text-lg text-gray-500">{$_('manage-admin-users')}</p>
<UsersOverview bind:current_users />
</section>
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')}
<AddUserModal bind:current_users bind:modal_open />
{/if}
@@ -1,33 +1,22 @@
<script>
import { ApiError, AuthService } from "@odit/lfk-client-js";
import { AuthService } from "@odit/lfk-client-js";
import toast from "svelte-french-toast";
import { _ } from "svelte-i18n";
import Toastify from "toastify-js";
import "toastify-js/src/toastify.css";
import isEmail from "validator/es/lib/isEmail";
let reset_mail_sent = false;
let usersEmail = "";
function reset() {
if (isEmail(usersEmail)) {
AuthService.authControllerGetResetToken({ email: usersEmail })
toast.loading($_("mail-validation-in-progress"));
AuthService.authControllerGetResetToken("de", { email: usersEmail })
.then((resp) => {
console.log(resp);
console.log(resp.resetToken);
Toastify({
text: $_("mail-validation-in-progress"),
duration: 3500,
}).showToast();
toast.dismiss();
reset_mail_sent = true;
})
.catch((err) => {
console.log(err.body.name);
console.log(err.body.message);
});
.catch((err) => {});
} else {
Toastify({
text: $_("invalid-mail-reset"),
duration: 3500,
}).showToast();
toast($_("invalid-mail-reset"));
}
}
</script>
@@ -37,19 +26,18 @@
<div class="max-w-md w-full py-12 px-6">
<img style="height:10rem;" class="mx-auto" src="/lfk-logo.png" alt="" />
<p class="mt-6 text-lg text-center font-bold text-gray-900">
{$_('application_name')}
{$_("application_name")}
</p>
<p class="mt-2 mb-2 text-sm text-center text-gray-900">
Passwort-Reset Mail wurde an
{usersEmail}
geschickt
{$_("password-reset-mail-sent", { values: { usersEmail: usersEmail } })}
</p>
<div class="mt-6">
<div class="mt-6">
<a
href="/"
class="block w-full text-center py-2 px-3 border border-gray-300 rounded-md text-gray-900 font-medium hover:border-gray-400 focus:outline-none focus:border-gray-400 sm:text-sm">
{$_('goback')}
class="block w-full text-center py-2 px-3 border border-gray-300 rounded-md text-gray-900 font-medium hover:border-gray-400 focus:outline-none focus:border-gray-400 sm:text-sm"
>
{$_("goback")}
</a>
</div>
</div>
@@ -60,25 +48,26 @@
<div class="max-w-md w-full py-12 px-6">
<img style="height:10rem;" class="mx-auto" src="/lfk-logo.png" alt="" />
<p class="mt-6 text-lg text-center font-bold text-gray-900">
{$_('application_name')}
{$_("application_name")}
</p>
<p class="mt-6 text-sm text-center text-gray-900">
{$_('forgot_password?')}
{$_("forgot_password")}
</p>
<p class="mt-2 mb-2 text-sm text-center text-gray-900">
{$_('dont-panic-were-resetting-it')}
{$_("dont-panic-were-resetting-it")}
</p>
<div>
<div class="rounded-md shadow-sm">
<div>
<input
aria-label={$_('e-mail-adress')}
aria-label={$_("e-mail-adress")}
name="email"
type="email"
required=""
class="border-gray-300 placeholder-gray-500 appearance-none rounded-none relative block w-full px-3 py-2 border text-gray-900 rounded-t-md focus:outline-none focus:shadow-outline-blue focus:border-blue-300 focus:z-10 sm:text-sm"
placeholder={$_('e-mail-adress')}
bind:value={usersEmail} />
placeholder={$_("e-mail-adress")}
bind:value={usersEmail}
/>
</div>
</div>
@@ -86,19 +75,22 @@
<button
on:click={reset}
type="submit"
class="relative block w-full py-2 px-3 border border-transparent rounded-md text-white font-semibold bg-gray-800 hover:bg-gray-700 focus:bg-gray-900 focus:outline-none focus:shadow-outline sm:text-sm">
class="relative block w-full py-2 px-3 border border-transparent rounded-md text-white font-semibold bg-gray-800 hover:bg-gray-700 focus:bg-gray-900 focus:outline-none focus:shadow-outline sm:text-sm"
>
<span class="absolute left-0 inset-y pl-3">
<svg
class="h-5 w-5 text-gray-500"
fill="currentColor"
viewBox="0 0 20 20">
viewBox="0 0 20 20"
>
<path
fill-rule="evenodd"
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
clip-rule="evenodd" />
clip-rule="evenodd"
/>
</svg>
</span>
{$_('reset-my-password')}
{$_("reset-my-password")}
</button>
</div>
<div class="mt-6">
@@ -107,24 +99,30 @@
<div class="w-full border-t border-gray-300" />
</div>
<div class="relative flex justify-center text-sm">
<span
class="px-2 bg-gray-100 text-gray-500">{$_('dont-have-your-email-connected')}</span>
<span class="px-2 bg-gray-100 text-gray-500"
>{$_("dont-have-your-email-connected")}</span
>
</div>
</div>
<span
class="mt-2 text-sm px-2 bg-gray-100 text-gray-500 justify-center relative flex">{$_('cannot-reset-your-password-directly')}</span>
class="mt-2 text-sm px-2 bg-gray-100 text-gray-500 justify-center relative flex"
>{$_("cannot-reset-your-password-directly")}</span
>
<div class="mt-6">
<a
href="mailto:lfk@odit.services"
class="block w-full text-center py-2 px-3 border border-gray-300 rounded-md text-gray-900 font-medium hover:border-gray-400 focus:outline-none focus:border-gray-400 sm:text-sm">
{$_('send-a-mail-to-lfk-odit-services')}
class="block w-full text-center py-2 px-3 border border-gray-300 rounded-md text-gray-900 font-medium hover:border-gray-400 focus:outline-none focus:border-gray-400 sm:text-sm"
>
{$_("send-a-mail-to-lfk-odit-services")}
</a>
</div>
<div class="mt-6">
<a
href="/"
class="block w-full text-center py-2 px-3 border border-gray-300 rounded-md text-gray-900 font-medium hover:border-gray-400 focus:outline-none focus:border-gray-400 sm:text-sm">{$_('goback')}</a>
class="block w-full text-center py-2 px-3 border border-gray-300 rounded-md text-gray-900 font-medium hover:border-gray-400 focus:outline-none focus:border-gray-400 sm:text-sm"
>{$_("goback")}</a
>
</div>
</div>
</div>
@@ -1,14 +1,15 @@
<script>
import store from "../store.js";
import store from "../../store.js";
import localForage from "localforage";
import { _ } from "svelte-i18n";
store.init();
import { OpenAPI, AuthService } from "@odit/lfk-client-js";
import Footer from "./Footer.svelte";
import Toastify from "toastify-js";
import Footer from "../general/Footer.svelte";
import isEmail from "validator/es/lib/isEmail";
import toast from "svelte-french-toast";
// ------
let username = "demo";
let password = "demo";
let username = config.default_username || "";
let password = config.default_password || "";
let is_blocked_by_autologin = false;
let last_loginclick_processed = true;
@@ -19,11 +20,6 @@
OpenAPI.TOKEN = value.access_token;
const jwtinfo = JSON.parse(atob(OpenAPI.TOKEN.split(".")[1]));
store.login(value, jwtinfo);
Toastify({
text: $_("welcome_wavinghand"),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
}
});
@@ -32,45 +28,38 @@
// prevent login button spamming
if (last_loginclick_processed && is_blocked_by_autologin === false) {
last_loginclick_processed = false;
Toastify({
text: $_("login_is_checked"),
duration: 500,
}).showToast();
AuthService.authControllerLogin({
username,
password,
})
toast.loading($_("login_is_checked"));
let postdata = {};
if (isEmail(username)) {
postdata = {
email: username,
password,
};
} else {
postdata = {
username,
password,
};
}
AuthService.authControllerLogin(postdata)
.then(async (result) => {
await localForage.setItem("logindata", result);
OpenAPI.TOKEN = result.access_token;
const jwtinfo = JSON.parse(atob(OpenAPI.TOKEN.split(".")[1]));
store.login(result.access_token, jwtinfo);
location.replace("/");
Toastify({
text: $_("welcome_wavinghand"),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
toast.dismiss();
})
.catch((err) => {
Toastify({
text: $_("error_on_login"),
duration: 500,
backgroundColor:
"linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)",
}).showToast();
toast.dismiss();
toast.error($_("error_on_login"));
})
.finally(() => {
last_loginclick_processed = true;
});
// last login was not processed yet
} else {
Toastify({
text: "chill...",
duration: 1500,
backgroundColor:
"linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)",
}).showToast();
toast($_("please-wait-a-moment-your-login-is-still-being-processed"));
}
};
function handleKeydown(e) {
@@ -81,34 +70,37 @@
</script>
<div
class="min-h-screen flex items-center justify-center bg-gray-100 text-gray-900">
class="min-h-screen flex items-center justify-center bg-gray-100 text-gray-900"
>
<div class="max-w-md w-full py-12 px-6" role="main">
<img style="height:10rem;" class="mx-auto" src="/lfk-logo.png" alt="" />
<p class="mt-6 text-lg text-center font-bold">{$_('application_name')}</p>
<p class="mt-6 text-sm text-center">{$_('log_in_to_your_account')}</p>
<p class="mt-6 text-xl text-center font-bold">{$_("application_name")}</p>
<p class="mt-2 mb-6 text-sm text-center">{$_("log_in_to_your_account")}</p>
<div>
<div class="rounded-md shadow-sm">
<div>
<!-- svelte-ignore a11y-autofocus -->
<input
autofocus
aria-label={$_('email_address_or_username')}
aria-label={$_("email_address_or_username")}
type="text"
required=""
class="border-gray-300 placeholder-gray-500 appearance-none rounded-none relative block w-full px-3 py-2 border rounded-t-md focus:outline-none focus:shadow-outline-blue focus:border-blue-300 focus:z-10 sm:text-sm"
on:keydown={handleKeydown}
placeholder={$_('email_address_or_username')}
bind:value={username} />
placeholder={$_("email_address_or_username")}
bind:value={username}
/>
</div>
<div class="-mt-px relative">
<input
aria-label={$_('password')}
aria-label={$_("password")}
type="password"
required=""
bind:value={password}
class="border-gray-300 placeholder-gray-500 appearance-none rounded-none relative block w-full px-3 py-2 border rounded-b-md focus:outline-none focus:shadow-outline-blue focus:border-blue-300 focus:z-10 sm:text-sm"
on:keydown={handleKeydown}
placeholder={$_('password')} />
placeholder={$_("password")}
/>
</div>
</div>
@@ -116,29 +108,33 @@
<button
on:click={login}
type="submit"
class="relative block w-full py-2 px-3 border border-transparent rounded-md text-white font-semibold bg-gray-800 hover:bg-gray-700 focus:bg-gray-900 focus:outline-none focus:shadow-outline sm:text-sm">
class="relative block w-full py-2 px-3 border border-transparent rounded-md text-white font-semibold bg-gray-800 hover:bg-gray-700 focus:bg-gray-900 focus:outline-none focus:shadow-outline sm:text-sm"
>
<span class="absolute left-0 inset-y pl-3">
<svg
class="h-5 w-5 text-gray-500"
fill="currentColor"
viewBox="0 0 20 20">
viewBox="0 0 20 20"
>
<path
fill-rule="evenodd"
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
clip-rule="evenodd" />
clip-rule="evenodd"
/>
</svg>
</span>
{$_('log_in')}
{$_("log_in")}
</button>
</div>
</div>
<div class="mt-2">
<!-- <div class="mt-2">
<a
href="/forgot_password"
class="block w-full text-center py-2 px-3 border border-gray-300 rounded-md font-medium hover:border-gray-400 focus:outline-none focus:border-gray-400 sm:text-sm">
{$_('forgot_password?')}
class="block w-full text-center py-2 px-3 border border-gray-300 rounded-md font-medium hover:border-gray-400 focus:outline-none focus:border-gray-400 sm:text-sm"
>
{$_("forgot_password")}
</a>
</div>
</div> -->
</div>
</div>
<Footer />
@@ -0,0 +1,52 @@
<script context="module">
import { passwordStrength } from "check-password-strength";
export function password_strong_enough(password_change) {
let strength = passwordStrength(password_change);
return (
strength?.contains.includes("lowercase") &&
strength?.contains.includes("uppercase") &&
strength?.contains.includes("number") &&
strength?.length > 9
);
}
export function password_strong_enough_and_equal(
password_change,
password_confirm
) {
return (
password_strong_enough(password_change) &&
password_change === password_confirm
);
}
</script>
<script>
import { getLocaleFromNavigator, _ } from "svelte-i18n";
import { passwordStrength as Strength } from "check-password-strength";
export let password_change;
export let password_confirm;
$: strength = Strength(password_change);
$: passwords_match =
!password_confirm || password_confirm === password_change;
</script>
<div class="ml-4">
<ul class="list-disc font-medium tracking-wide text-red-500 text-xs">
{#if !strength.contains.includes("lowercase")}
<li>{$_("must-contain-a-lowercase-letter")}</li>
{/if}
{#if !strength.contains.includes("uppercase")}
<li>{$_("must-contain-a-uppercase-letter")}</li>
{/if}
{#if !strength.contains.includes("number")}
<li>{$_("must-contain-a-number")}</li>
{/if}
{#if !(strength.length > 9)}
<li>{$_("must-be-at-least-10-characters-long")}</li>
{/if}
{#if !(passwords_match == true)}
<li>{$_("passwords-dont-match")}</li>
{/if}
</ul>
</div>
+135
View File
@@ -0,0 +1,135 @@
<script>
import { AuthService } from "@odit/lfk-client-js";
import { _ } from "svelte-i18n";
import toast from "svelte-french-toast";
import PasswordStrength, {
password_strong_enough,
} from "../auth/PasswordStrength.svelte";
let state = "reset_in_progress";
let password = "";
export let params;
function set_new_password() {
if (password.trim() !== "") {
toast.loading($_("password-reset-in-progress"));
AuthService.authControllerResetPassword(atob(params.resetkey), {
password,
})
.then((resp) => {
toast.dismiss();
toast($_("password-reset-successful"));
state = "reset_success";
})
.catch((err) => {
state = "reset_error";
});
} else {
toast.dismiss();
toast.error($_("please-provide-a-password"));
}
}
</script>
{#if state === "reset_success"}
<div class="min-h-screen flex items-center justify-center bg-gray-100">
<div class="max-w-md w-full py-12 px-6">
<img style="height:10rem;" class="mx-auto" src="/lfk-logo.png" alt="" />
<p class="mt-6 text-lg text-center font-bold text-gray-900">
{$_("application_name")}
</p>
<p class="mt-2 mb-2 text-sm text-center text-gray-900 font-bold">
{$_("successful-password-reset")}
</p>
<p class="mt-2 mb-2 text-sm text-center text-gray-900">
{$_("you-can-now-use-your-new-password-to-log-in-to-your-account")}
</p>
<div class="mt-6">
<div class="mt-6">
<a
href="/login/"
class="text-center relative block w-full py-2 px-3 border border-transparent rounded-md text-white font-semibold bg-gray-800 hover:bg-gray-700 focus:bg-gray-900 focus:outline-none focus:shadow-outline sm:text-sm"
>
{$_("go-to-login")}
</a>
</div>
</div>
</div>
</div>
{:else if state === "reset_error"}
<div class="min-h-screen flex items-center justify-center bg-gray-100">
<div class="max-w-md w-full py-12 px-6">
<img style="height:10rem;" class="mx-auto" src="/lfk-logo.png" alt="" />
<p class="mt-6 text-lg text-center font-bold text-gray-900">
{$_("application_name")}
</p>
<p class="mt-2 mb-2 text-sm text-center text-gray-900 font-bold">
{$_("password-reset-failed")}
</p>
<p class="mt-2 mb-2 text-sm text-center text-gray-900">
{$_("please-request-a-new-reset-mail")}
</p>
<div class="mt-6">
<div class="mt-6">
<a
href="/forgot_password/"
class="text-center relative block w-full py-2 px-3 border border-transparent rounded-md text-white font-semibold bg-gray-800 hover:bg-gray-700 focus:bg-gray-900 focus:outline-none focus:shadow-outline sm:text-sm"
>
{$_("request-a-new-reset-mail")}
</a>
</div>
</div>
</div>
</div>
{:else if state === "reset_in_progress"}
<div class="min-h-screen flex items-center justify-center bg-gray-100">
<div class="max-w-md w-full py-12 px-6">
<img style="height:10rem;" class="mx-auto" src="/lfk-logo.png" alt="" />
<p class="mt-6 text-lg text-center font-bold text-gray-900">
{$_("application_name")}
</p>
<p class="mt-2 mb-4 text-md text-center text-gray-900">
{$_("reset-password")}
</p>
<div>
<div class="rounded-md shadow-sm">
<div>
<input
aria-label={$_("new-password")}
name="password"
type="password"
required=""
class="border-gray-300 placeholder-gray-500 appearance-none rounded-md relative block w-full px-3 py-2 border text-gray-900 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 focus:z-10 sm:text-sm"
placeholder={$_("new-password")}
bind:value={password}
/>
</div>
<PasswordStrength bind:password_change={password} />
</div>
<div class="mt-5">
<button
on:click={set_new_password}
disabled={!password_strong_enough(password)}
class:opacity-50={!password_strong_enough(password)}
type="submit"
class="relative block w-full py-2 px-3 border border-transparent rounded-md text-white font-semibold bg-gray-800 hover:bg-gray-700 focus:bg-gray-900 focus:outline-none focus:shadow-outline sm:text-sm"
>
<span class="absolute left-0 inset-y pl-3">
<svg
class="h-5 w-5 text-gray-500"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fill-rule="evenodd"
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
clip-rule="evenodd"
/>
</svg>
</span>
{$_("reset-my-password")}
</button>
</div>
</div>
</div>
</div>
{/if}
@@ -4,19 +4,22 @@
<body class="antialiased font-sans">
<div class="flex min-h-screen">
<div class="w-full bg-white flex items-center justify-center ">
<div class="w-full bg-white flex items-center justify-center">
<div class="max-w-sm m-8">
<div class="text-black text-5xl md:text-15xl font-black">
Internal Error
{$_("internal-error")}
</div>
<div class="w-16 h-1 bg-purple-light my-3 md:my-6" />
<p
class="text-grey-darker text-2xl md:text-3xl font-light mb-8 leading-normal">
Something went wrong in the UI logic
class="text-grey-darker text-2xl md:text-3xl font-light mb-8 leading-normal"
>
{$_("generic-ui-logic-error")}
</p>
<a
href="/"
class="bg-transparent text-grey-darkest font-bold uppercase tracking-wide py-3 px-6 border-2 border-grey-light hover:border-grey rounded-lg">{$_('goback')}</a>
class="bg-transparent text-grey-darkest font-bold uppercase tracking-wide py-3 px-6 border-2 border-grey-light hover:border-grey rounded-lg"
>{$_("goback")}</a
>
</div>
</div>
</div>
@@ -5,7 +5,7 @@
<div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500">
<span class="inline-block align-middle mr-8">
<b class="capitalize">{$_('general_promise_error')}</b>
<b class="capitalize">{$_("general_promise_error")}</b>
{error}
</span>
</div>
+25
View File
@@ -0,0 +1,25 @@
export function getlang(langkeys) {
return {
search: {
placeholder: langkeys.search,
},
sort: {
sortAsc: langkeys.sort_column_ascending,
sortDesc: langkeys.sort_column_descending,
},
pagination: {
previous: langkeys.previous,
next: langkeys.next,
navigate: (page, pages) =>
`${langkeys.page} ${page} ${langkeys.of} ${pages}`,
page: (page) => `${langkeys.page} ${page}`,
showing: langkeys.showing,
of: langkeys.of,
to: langkeys.to,
results: langkeys.records,
},
loading: langkeys.loading,
noRecordsFound: langkeys.no_matching_records_found,
error: langkeys.an_error_happened_while_fetching_the_data,
};
}
+6
View File
@@ -0,0 +1,6 @@
<!--
Temporary tailwind import fixes for classes that wouldn't be directly used otherwise.
Or as others may call it: Real big bullshit time.
Issue: https://git.odit.services/lfk/frontend/issues/136
-->
<div class="opacity-50" />
+10
View File
@@ -0,0 +1,10 @@
/** Dispatch event on click outside of node */
export function clickOutside(node) {
const handleClick = (event) => {
if (event.target.getAttribute("data-id") === "modal_backdrop") {
node.dispatchEvent(new CustomEvent("click_outside", node));
}
};
document.removeEventListener("click", handleClick, true);
document.addEventListener("click", handleClick, true);
}
+323
View File
@@ -0,0 +1,323 @@
.simplecontent * {
margin: 0;
padding: 0;
}
.simplecontent address,
.simplecontent area,
.simplecontent article,
.simplecontent aside,
.simplecontent audio,
.simplecontent blockquote,
.simplecontent datalist,
.simplecontent details,
.simplecontent dl,
.simplecontent fieldset,
.simplecontent figure,
.simplecontent form,
.simplecontent iframe,
.simplecontent img,
.simplecontent input,
.simplecontent meter,
.simplecontent nav,
.simplecontent ol,
.simplecontent optgroup,
.simplecontent option,
.simplecontent output,
.simplecontent p,
.simplecontent pre,
.simplecontent progress,
.simplecontent ruby,
.simplecontent section,
.simplecontent table,
.simplecontent textarea,
.simplecontent ul,
.simplecontent video {
margin-bottom: 1rem;
}
.simplecontent button,
.simplecontent html,
.simplecontent input,
.simplecontent select {
font-family: var(--nc-font-sans);
}
.simplecontent body {
margin: 0 auto;
max-width: 750px;
padding: 2rem;
border-radius: 6px;
overflow-x: hidden;
word-break: break-word;
overflow-wrap: break-word;
background: var(--nc-bg-1);
color: var(--nc-tx-2);
font-size: 1.03rem;
line-height: 1.5;
}
.simplecontent h1,
.simplecontent h2,
.simplecontent h3,
.simplecontent h4,
.simplecontent h5,
.simplecontent h6 {
line-height: 1;
color: var(--nc-tx-1);
padding-top: 0.875rem;
}
.simplecontent h1,
.simplecontent h2,
.simplecontent h3 {
color: var(--nc-tx-1);
padding-bottom: 2px;
margin-bottom: 8px;
border-bottom: 1px solid var(--nc-bg-2);
}
.simplecontent h4,
.simplecontent h5,
.simplecontent h6 {
margin-bottom: 0.3rem;
}
.simplecontent h1 {
font-size: 2.25rem;
}
.simplecontent h2 {
font-size: 1.85rem;
}
.simplecontent h3 {
font-size: 1.55rem;
}
.simplecontent h4 {
font-size: 1.25rem;
}
.simplecontent h5 {
font-size: 1rem;
}
.simplecontent h6 {
font-size: 0.875rem;
}
.simplecontent a {
color: #3d5af1;
}
.simplecontent a:hover {
color: var(--nc-lk-2);
}
.simplecontent abbr:hover {
cursor: help;
}
.simplecontent blockquote {
padding: 1.5rem;
background: #ddd;
border-left: 5px solid var(--nc-bg-3);
}
.simplecontent abbr {
cursor: help;
}
.simplecontent blockquote :last-child {
padding-bottom: 0;
margin-bottom: 0;
}
.simplecontent header {
background: #ddd;
border-bottom: 1px solid var(--nc-bg-3);
padding: 2rem 1.5rem;
margin: -2rem calc(0px - (50vw - 50%)) 2rem;
padding-left: calc(50vw - 50%);
padding-right: calc(50vw - 50%);
}
.simplecontent header h1,
.simplecontent header h2,
.simplecontent header h3 {
padding-bottom: 0;
border-bottom: 0;
}
.simplecontent header > :first-child {
margin-top: 0;
padding-top: 0;
}
.simplecontent header > :last-child {
margin-bottom: 0;
}
.simplecontent a button,
.simplecontent button,
.simplecontent input[type="button"],
.simplecontent input[type="reset"],
.simplecontent input[type="submit"] {
font-size: 1rem;
display: inline-block;
padding: 6px 12px;
text-align: center;
text-decoration: none;
white-space: nowrap;
background: #3d5af1;
color: var(--nc-lk-tx);
border: 0;
border-radius: 4px;
box-sizing: border-box;
cursor: pointer;
color: var(--nc-lk-tx);
}
.simplecontent a button[disabled],
.simplecontent button[disabled],
.simplecontent input[type="button"][disabled],
.simplecontent input[type="reset"][disabled],
.simplecontent input[type="submit"][disabled] {
cursor: default;
opacity: 0.5;
cursor: not-allowed;
}
.simplecontent .button:focus,
.simplecontent .button:hover,
.simplecontent button:focus,
.simplecontent button:hover,
.simplecontent input[type="button"]:focus,
.simplecontent input[type="button"]:hover,
.simplecontent input[type="reset"]:focus,
.simplecontent input[type="reset"]:hover,
.simplecontent input[type="submit"]:focus,
.simplecontent input[type="submit"]:hover {
background: var(--nc-lk-2);
}
.simplecontent code,
.simplecontent kbd,
.simplecontent pre,
.simplecontent samp {
font-family: var(--nc-font-mono);
}
.simplecontent code,
.simplecontent kbd,
.simplecontent pre,
.simplecontent samp {
background: #ddd;
border: 1px solid var(--nc-bg-3);
border-radius: 4px;
padding: 3px 6px;
font-size: 0.9rem;
}
.simplecontent kbd {
border-bottom: 3px solid var(--nc-bg-3);
}
.simplecontent pre {
padding: 1rem 1.4rem;
max-width: 100%;
overflow: auto;
}
.simplecontent pre code {
background: inherit;
font-size: inherit;
color: inherit;
border: 0;
padding: 0;
margin: 0;
}
.simplecontent code pre {
display: inline;
background: inherit;
font-size: inherit;
color: inherit;
border: 0;
padding: 0;
margin: 0;
}
.simplecontent details {
padding: 0.6rem 1rem;
background: #ddd;
border: 1px solid var(--nc-bg-3);
border-radius: 4px;
}
.simplecontent summary {
cursor: pointer;
font-weight: 700;
}
.simplecontent details[open] {
padding-bottom: 0.75rem;
}
.simplecontent details[open] summary {
margin-bottom: 6px;
}
.simplecontent details[open] > :last-child {
margin-bottom: 0;
}
.simplecontent dt {
font-weight: 700;
}
.simplecontent dd::before {
content: "→ ";
}
.simplecontent hr {
border: 0;
border-bottom: 1px solid var(--nc-bg-3);
margin: 1rem auto;
}
.simplecontent fieldset {
margin-top: 1rem;
padding: 2rem;
border: 1px solid var(--nc-bg-3);
border-radius: 4px;
}
.simplecontent legend {
padding: auto 0.5rem;
}
.simplecontent table {
border-collapse: collapse;
width: 100%;
}
.simplecontent td,
.simplecontent th {
border: 1px solid var(--nc-bg-3);
text-align: left;
padding: 0.5rem;
}
.simplecontent th {
background: #ddd;
}
.simplecontent tr:nth-child(even) {
background: #ddd;
}
.simplecontent table caption {
font-weight: 700;
margin-bottom: 0.5rem;
}
.simplecontent textarea {
max-width: 100%;
}
.simplecontent ol,
.simplecontent ul {
padding-left: 2rem;
}
.simplecontent li {
margin-top: 0.4rem;
}
.simplecontent ol ol,
.simplecontent ol ul,
.simplecontent ul ol,
.simplecontent ul ul {
margin-bottom: 0;
}
.simplecontent mark {
padding: 3px 6px;
background: var(--nc-ac-1);
color: var(--nc-ac-tx);
}
.simplecontent input,
.simplecontent select,
.simplecontent textarea {
padding: 6px 12px;
margin-bottom: 0.5rem;
background: #ddd;
color: var(--nc-tx-2);
border: 1px solid var(--nc-bg-3);
border-radius: 4px;
box-shadow: none;
box-sizing: border-box;
}
.simplecontent img {
max-width: 100%;
}
.simplecontent blockquote {
background: #ececec;
}
.simplecontent ol {
list-style-type: decimal;
}
.simplecontent ul {
list-style-type: circle;
}
@@ -0,0 +1,218 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { RunnerCardService } from "@odit/lfk-client-js";
import { createEventDispatcher } from "svelte";
import toast from "svelte-french-toast";
import DocumentServer from "../pdf_generation/DocumentServer";
export let bulk_modal_open;
const dispatch = createEventDispatcher();
const documentServer = new DocumentServer(config.baseurl_documentserver,config.documentserver_key);
$: card_count = 0;
$: is_card_count_valid = card_count > 0;
$: processed_last_submit = true;
$: createbtnenabled = is_card_count_valid;
(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
bulk_modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit_with_print();
}
}
};
})();
function submit_without_print() {
if (processed_last_submit === true) {
processed_last_submit = false;
toast.loading($_("creating-blanco-cards"));
RunnerCardService.runnerCardControllerPostBlancoBulk(card_count, true)
.then((result) => {
bulk_modal_open = false;
//
toast.dismiss();
toast.success($_("created-blanco-cards"));
dispatch("created", { cards: result });
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
});
}
}
function submit_with_print() {
if (processed_last_submit === true) {
processed_last_submit = false;
toast.dismiss();
toast.loading($_("creating-blanco-cards"));
RunnerCardService.runnerCardControllerPostBlancoBulk(card_count, true)
.then((result) => {
bulk_modal_open = false;
//
toast.dismiss();
toast.success($_("created-blanco-cards"));
toast.loading($_("generating-pdf"));
dispatch("created", { cards: result });
documentServer.generateCards(result, "de")
.then((blob) => {
const url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = "Bulkcards.pdf";
document.body.appendChild(a);
a.click();
a.remove();
toast.dismiss();
toast.success($_("pdf-successfully-generated"));
})
.catch((err) => {
console.error(err);
});
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
});
}
}
</script>
{#if bulk_modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
bulk_modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-4 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-2xl sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w- rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_("create-bulk-blanco-cards")}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_(
"just-enter-how-many-you-want-and-the-system-will-create-them"
)}
</p>
</div>
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6">
<label
for="amount"
class="block text-sm font-medium text-gray-700"
>{$_("amount")}</label
>
<div class="mt-1 flex rounded-md shadow-sm">
<input
autocomplete="off"
class:border-red-500={!is_card_count_valid}
class:focus:border-red-500={!is_card_count_valid}
class:focus:ring-red-500={!is_card_count_valid}
bind:value={card_count}
type="number"
step="1"
name="amount"
class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 p-2"
placeholder="400"
/>
<span
class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm"
>{$_("cards")}</span
>
</div>
{#if !is_card_count_valid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("you-must-create-at-least-one-card-or-cancel")}
</span>
{/if}
</div>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 grid gap-2 rounded-b">
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit_with_print}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("create-and-generate-pdf")}
</button>
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit_without_print}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-400 text-base font-medium text-white hover:bg-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("create-without-pdf")}
</button>
<button
on:click={() => {
bulk_modal_open = false;
}}
type="button"
class="mr-auto mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}
+191
View File
@@ -0,0 +1,191 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { RunnerCardService, RunnerService } from "@odit/lfk-client-js";
import Select from "svelte-select";
import { createEventDispatcher } from "svelte";
import toast from "svelte-french-toast";
export let modal_open;
const dispatch = createEventDispatcher();
const getRunnerLabel = (option) => {
if (option.middlename) {
return option.firstname + " " + option.middlename + " " + option.lastname;
}
return option.firstname + " " + option.lastname;
};
const filterRunners = (label, filterText, option) => {
if (filterText.startsWith("#")) {
return option.value.id == parseInt(filterText.replace("#", ""));
}
return (
label.toLowerCase().includes(filterText.toLowerCase()) ||
option.value.toString().startsWith(filterText.toLowerCase())
);
};
function focus(el) {
el.focus();
}
$: runner = 0;
$: enabled = true;
$: processed_last_submit = true;
let loading = true;
let runners = [];
RunnerService.runnerControllerGetAll().then((val) => {
runners = val.map((r) => {
return { label: getRunnerLabel(r), value: r };
});
loading = false;
});
$: createbtnenabled = true;
(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
})();
function submit() {
if (processed_last_submit === true) {
processed_last_submit = false;
toast.loading($_("adding-card"));
let postdata = {
runner,
enabled,
};
RunnerCardService.runnerCardControllerPost(postdata)
.then((result) => {
runner = 0;
modal_open = false;
//
toast.dismiss();
toast.success($_("card-added"));
dispatch("created", { cards: [result] });
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
});
}
}
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-4 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-md text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_("create-a-new-card")}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_("you-can-provide-a-runner-but-you-dont-have-to")}
{$_(
"if-you-want-to-create-multiple-blanco-cards-try-the-add-bulk-button"
)}
</p>
</div>
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6">
<label
for="donor"
class="block text-sm font-medium text-gray-700"
>{$_("runner")}</label
>
<Select
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
itemFilter={(label, filterText, option) =>
filterRunners(label, filterText, option)}
items={runners}
bind:loading
showChevron={!loading}
placeholder={$_("search-for-runner-by-name-or-id")}
noOptionsMessage={$_("no-runners-found")}
on:select={(selectedValue) =>
(runner = selectedValue.detail.value.id)}
on:clear={() => (runner = null)}
/>
</div>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 grid gap-2 rounded-b">
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("create")}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}
+200
View File
@@ -0,0 +1,200 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { RunnerCardService, RunnerService } from "@odit/lfk-client-js";
import Select from "svelte-select";
import { createEventDispatcher } from "svelte";
import toast from "svelte-french-toast";
export let edit_modal_open;
export let runner = {};
export let editable = {};
export let original_data = {};
const getRunnerLabel = (option) =>
option.firstname + " " + (option.middlename || "") + " " + option.lastname;
const filterRunners = (label, filterText, option) => {
if (filterText.startsWith("#")) {
return option.value.id == parseInt(filterText.replace("#", ""));
}
return (
label.toLowerCase().includes(filterText.toLowerCase()) ||
option.value.toString().startsWith(filterText.toLowerCase())
);
};
function focus(el) {
el.focus();
}
$: runners = [];
$: enabled = true;
$: processed_last_submit = true;
const dispatch = createEventDispatcher();
RunnerService.runnerControllerGetAll().then((val) => {
runners = val.map((r) => {
return { label: getRunnerLabel(r), value: r };
});
});
$: createbtnenabled = !(
JSON.stringify(editable) === JSON.stringify(original_data)
);
(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
edit_modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
})();
function submit() {
if (processed_last_submit === true) {
processed_last_submit = false;
toast.loading($_("updating-card"));
RunnerCardService.runnerCardControllerPut(original_data.id, editable)
.then((result) => {
runner = {};
editable = {};
original_data = {};
edit_modal_open = false;
//
toast.dismiss();
toast.success($_("card-updated"));
dispatch("dataUpdated", { card: result });
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
});
}
}
</script>
{#if edit_modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
edit_modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-4 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-md text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_("edit-a-card")}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_("you-can-provide-a-runner-but-you-dont-have-to")}
</p>
</div>
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6">
<label
for="runner"
class="block text-sm font-medium text-gray-700"
>{$_("runner")}</label
>
<Select
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
itemFilter={(label, filterText, option) =>
filterRunners(label, filterText, option)}
items={runners}
showChevron={true}
placeholder={$_("search-for-runner-by-name-or-id")}
noOptionsMessage={$_("no-runners-found")}
bind:selectedValue={runner}
on:select={(selectedValue) =>
(editable.runner = selectedValue.detail.value.id)}
on:clear={() => (editable.runner = null)}
/>
</div>
<div class="col-span-6">
<p class="text-gray-500">
<input
id="enabled"
on:change={() => {
editable.enabled = !editable.enabled;
}}
name="enabled"
type="checkbox"
checked={editable.enabled}
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
/>
{$_("this-card-is")}
{#if editable.enabled}
{$_("enabled")}
{:else}{$_("disabled")}{/if}
</p>
</div>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 grid gap-2 rounded-b">
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("save-changes")}
</button>
<button
on:click={() => {
edit_modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}
+16
View File
@@ -0,0 +1,16 @@
<script>
import { _ } from "svelte-i18n";
export let runner;
</script>
{#if !runner}
{$_("non-blanko")}
{:else}
<a href={`/runners/${runner.id}`}>
{#if runner.middlename}
{runner.firstname} {runner.middlename} {runner.lastname}
{:else}
{runner.firstname} {runner.lastname}
{/if}
</a>
{/if}
+16
View File
@@ -0,0 +1,16 @@
<script>
import { _ } from "svelte-i18n";
export let enabled = false;
</script>
{#if enabled}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-green-100 text-green-800"
>{$_("enabled")}</span
>
{:else}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-red-100 text-red-800"
>{$_("disabled")}</span
>
{/if}
+53
View File
@@ -0,0 +1,53 @@
<script>
import { _ } from "svelte-i18n";
import store from "../../store";
import AddCardBulkModal from "./AddCardBulkModal.svelte";
import AddCardModal from "./AddCardModal.svelte";
import CardsOverview from "./CardsOverview.svelte";
$: current_cards = [];
export let modal_open = false;
export let bulk_modal_open = false;
let addCards;
</script>
<section class="container p-5">
<h4 class="mb-1 text-3xl font-extrabold leading-tight">
{$_("cards")}
</h4>
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:CREATE")}
<button
on:click={() => {
modal_open = true;
}}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:w-auto sm:text-sm mb-1 lg:mb-0"
>
{$_("add-card")}
</button>
<button
on:click={() => {
bulk_modal_open = true;
}}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:w-auto sm:text-sm mb-1 lg:mb-0"
>
{$_("create-bulk-cards")}
</button>
{/if}
<CardsOverview bind:current_cards bind:addCards />
</section>
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:CREATE")}
<AddCardModal
bind:modal_open
on:created={(event) => {
addCards(event.detail.cards);
}}
/>
<AddCardBulkModal
bind:bulk_modal_open
on:created={(event) => {
addCards(event.detail.cards);
}}
/>
{/if}
@@ -0,0 +1,12 @@
<script>
import { _ } from "svelte-i18n";
import cards_empty from "./cards.svg";
</script>
<div class="text-center items-center justify-center">
<p class="mb-16 text-lg text-gray-500">
<img class="m-auto mt-2" style="height:15rem" src={cards_empty} alt="" />
<span class="font-bold">{$_("there-are-no-cards-yet")}</span><br />
<span>{$_("add-your-first-card")}</span>
</p>
</div>
+316
View File
@@ -0,0 +1,316 @@
<script>
import { _ } from "svelte-i18n";
import { RunnerCardService } from "@odit/lfk-client-js";
import store from "../../store";
import toast from "svelte-french-toast";
import CardsEmptyState from "./CardsEmptyState.svelte";
import CardDetailModal from "./CardDetailModal.svelte";
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
import InputElement from "../shared/InputElement.svelte";
import {
createSvelteTable,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
renderComponent,
} from "@tanstack/svelte-table";
import { writable } from "svelte/store";
import TableBottom from "../shared/TableBottom.svelte";
import TableActions from "../shared/TableActions.svelte";
import TableHeader from "../shared/TableHeader.svelte";
import CardStatus from "./CardStatus.svelte";
import CardRunner from "./CardRunner.svelte";
import { onMount } from "svelte";
import { runnerFilter, statusFilter } from "../shared/tablefilters";
import DeleteCardModal from "./DeleteCardModal.svelte";
export let edit_modal_open = false;
export let runner = {};
export let editable = {};
export let original_data = {};
export let current_cards = [];
export const addCards = (cards) => {
current_cards = current_cards.concat(...cards);
options.update((options) => ({
...options,
data: current_cards,
}));
};
$: dataLoaded = false;
$: selected =
$table?.getSelectedRowModel().rows.map((row) => row.index) || [];
$: selectedCards =
$table?.getSelectedRowModel().rows.map((row) => row.original) || [];
$: active_delete = undefined;
$: cards_show = generate_cards.length > 0;
$: generate_cards = [];
const columns = [
{
accessorKey: "code",
header: () => $_("code"),
filterFn: `includesString`,
},
{
accessorKey: "runner",
header: () => $_("runner"),
cell: (info) => {
return renderComponent(CardRunner, { runner: info.getValue() });
},
filterFn: `runner`,
},
{
accessorKey: "enabled",
cell: (info) => {
return renderComponent(CardStatus, { enabled: info.getValue() });
},
header: () => $_("status"),
filterFn: `status`,
},
{
accessorKey: "actions",
header: () => $_("action"),
cell: (info) => {
return renderComponent(TableActions, {
detailsAction: () => {
open_edit_modal(
current_cards[
current_cards.findIndex((r) => r.id == info.row.original.id)
]
);
},
deleteAction: () => {
active_delete =
current_cards[
current_cards.findIndex((r) => r.id == info.row.original.id)
];
},
deleteEnabled:
store.state.jwtinfo.userdetails.permissions.includes("CARD:DELETE"),
});
},
enableColumnFilter: false,
enableSorting: false,
},
];
const options = writable({
data: [],
columns: columns,
initialState: {
pagination: {
pageSize: 50,
},
},
filterFns: {
runner: runnerFilter,
status: statusFilter,
},
enableRowSelection: true,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
});
const table = createSvelteTable(options);
function open_edit_modal(card) {
const getRunnerLabel = (option) =>
option.firstname +
" " +
(option.middlename || "") +
" " +
option.lastname;
if (card.runner?.id) {
runner = Object.assign(
{ runner },
{ label: getRunnerLabel(card.runner), value: card.runner }
);
card.runner = card.runner.id;
} else {
card.runner = null;
runner = null;
}
editable = Object.assign(editable, card);
original_data = Object.assign(original_data, card);
edit_modal_open = true;
}
async function deleteCard(delete_card_id) {
await RunnerCardService.runnerCardControllerRemove(delete_card_id, true);
current_cards = current_cards.filter((r) => r.id !== delete_card_id);
options.update((options) => ({
...options,
data: current_cards,
}));
toast.success($_("card-deleted"));
}
onMount(async () => {
let page = 0;
let pagesize = 500;
while (page >= 0) {
const cards = await RunnerCardService.runnerCardControllerGetAll(
page,
pagesize
);
if (cards.length == 0) {
page = -2;
}
current_cards = current_cards.concat(...cards);
options.update((options) => ({
...options,
data: current_cards,
}));
dataLoaded = true;
page++;
}
});
</script>
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:UPDATE")}
<CardDetailModal
bind:edit_modal_open
bind:runner
bind:editable
bind:original_data
on:dataUpdated={(event) => {
current_cards[
current_cards.findIndex((c) => c.id === event.detail.card.id)
] = event.detail.card;
current_cards = current_cards;
options.update((options) => ({
...options,
data: current_cards,
}));
}}
/>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:GET")}
<DeleteCardModal
delete_card={active_delete}
modal_open={active_delete != undefined}
on:delete={(event) => {
deleteCard(event.detail.id);
}}
/>
{#if !dataLoaded}
<div
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
role="alert"
>
<p class="font-bold">{$_("loading-cards")}</p>
<p class="text-sm">{$_("this-might-take-a-moment")}</p>
</div>
{:else if current_cards.length === 0}
<CardsEmptyState />
{:else}
<div class="h-12 mt-1">
{#if selected.length > 0}
<button
type="button"
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm inline-flex"
id="options-menu"
on:click={async () => {
const prom = [];
for (const card of selectedCards) {
prom.push(
await RunnerCardService.runnerCardControllerRemove(
card.id,
true
)
);
}
await Promise.all(prom);
for (const card of selectedCards) {
current_cards = current_cards.filter((r) => r.id !== card.id);
}
options.update((options) => ({
...options,
data: current_cards,
}));
$table.resetRowSelection();
}}
>
{$_("delete-cards")}
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-5 h-5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
/>
</svg>
</button>
{/if}
<GenerateRunnerCards
cards_show={selected.length > 0}
bind:generate_cards={selectedCards}
/>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead class="border-b border-gray-400">
{#each $table.getHeaderGroups() as headerGroup}
<tr class="select-none">
<th class="inset-y-0 left-0 px-4 py-2 text-left w-px">
<InputElement
type="checkbox"
checked={$table.getIsAllRowsSelected()}
indeterminate={$table.getIsSomeRowsSelected()}
on:change={() => $table.toggleAllRowsSelected()}
/>
</th>
{#each headerGroup.headers as header}
<TableHeader {header} />
{/each}
</tr>
{/each}
</thead>
<tbody>
{#each $table.getRowModel().rows as row}
<tr class="odd:bg-white even:bg-gray-100">
<td class="inset-y-0 left-0 px-4 py-2 text-center w-px">
<InputElement
type="checkbox"
checked={row.getIsSelected()}
on:change={() => row.toggleSelected()}
/>
</td>
{#each row.getVisibleCells() as cell}
<td>
<svelte:component
this={flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
/>
</td>
{/each}
</tr>
{/each}
</tbody>
</table>
</div>
<TableBottom {table} {selected} />
{/if}
{/if}
<style>
table tbody tr td:nth-child(2) {
font-family: monospace;
}
</style>
+123
View File
@@ -0,0 +1,123 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { createEventDispatcher, onMount } from "svelte";
export let modal_open;
export let delete_card = {
id: 0,
code: "",
runner: {
firstname: "",
lastname: "",
},
};
const dispatch = createEventDispatcher();
onMount(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
});
async function submit() {
dispatch("delete", { id: delete_card.id });
modal_open = false;
}
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-4 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-md text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_("please-confirm-the-deletion-of-card")}
</h3>
<div class="w-full">
{$_("card")} #{delete_card.code}<br />
<span class="inline-block">
{$_("runner")}:
{#if delete_card.runner}
<span class="inline-block"
>{delete_card.runner.firstname}
{delete_card.runner.lastname}</span
>
{:else}
{$_("non-blanko")}
{/if}</span
>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 grid gap-2 rounded-b">
<button
on:click={submit}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("delete")}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}
+1
View File
@@ -0,0 +1 @@
<svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 653.9 247.6"><path d="M272 211l-53 12s-11-2-1-17l4-4 27-14v-2l-6-41-2-16 17-17 4-3 44 41v1l-19 33z" fill="#ffb7b7"/><path d="M253 198l-54 13a6 6 0 01-5-7 16 16 0 012-5 48 48 0 016-9l28-14-4-24-1-12-2-8-2-16 21-19 22 21 22 20-3 5-3 7-17 30-3 6z" fill="#ffb7b7"/><path d="M346 190s-20-1-28-15a24 24 0 01-3-14l-8-17-11-23-30-4-2 1-21 19-7 6-10 9-49 44a37 37 0 01-7 9 50 50 0 01-9 7c-10 5-24 9-44 7L10 248 0 176l89-29 131-86 89 23 41 58z" fill="#ffb7b7"/><path d="M648 0H275a5 5 0 00-5 5v221a5 5 0 005 6h373a5 5 0 006-6V5a5 5 0 00-6-5z" fill="#fff"/><path d="M648 0H275a5 5 0 00-5 5v221a5 5 0 005 6h373a5 5 0 006-6V5a5 5 0 00-6-5zm4 226a4 4 0 01-4 4H275a4 4 0 01-3-4V5a4 4 0 013-3h373a4 4 0 014 3z" fill="#3f3d56"/><path d="M312 30a9 9 0 119-9 9 9 0 01-9 9zm0-17a8 8 0 107 8 8 8 0 00-7-8z" fill="#6c63ff"/><path d="M297 21a8 8 0 016-8 8 8 0 100 16 8 8 0 01-6-8zM349 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM368 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM386 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM415 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM434 130a7 7 0 01-7-7v-20a7 7 0 0113 0v20a7 7 0 01-6 7zM452 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM481 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM499 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM518 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM546 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM565 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM583 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7z" fill="#6c63ff"/><path d="M396 208h-99a5 5 0 110-10h99a5 5 0 010 10zM364 188h-35a5 5 0 110-10h35a5 5 0 110 10z" fill="#e6e6e6"/><path fill="#3f3d56" d="M271 46h381v2H271z"/><path opacity=".1" d="M228 203l-1-2 33-15 8-27-12-10 1-1 13 10-8 30-34 15zM196 199l-9 4-17 2a50 50 0 01-9 7l-16-1-26-1 88-74 18 4-29 59z"/><path d="M318 175l-8 1-47 4-29 1-38 18-9 4-70 8 95-81 11 2 20 5 22 5 18 1 24 1 20 1a13 13 0 0112 13c0 7-5 14-21 17z" fill="#ffb7b7"/><path d="M325 170s-7-2-9-9c-2-4-1-9 3-15l1 1c-3 6-4 10-3 14 2 5 9 7 9 7zM197 197l34-16v2l-33 16zM218 135l48-19v2l-41 16 35 6v2l-42-7z" opacity=".1"/></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -0,0 +1,480 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import {
GroupContactService,
RunnerTeamService,
RunnerOrganizationService,
} from "@odit/lfk-client-js";
import isEmail from "validator/es/lib/isEmail";
import isMobilePhone from "validator/es/lib/isMobilePhone";
import toast from "svelte-french-toast";
export let modal_open;
export let current_contacts;
$: selected_team = [];
let firstname_input;
let lastname_input;
let middlename_input;
let phone_input;
let email_input;
let address_input1;
let address_input2;
let address_zipcode;
let address_city;
let teams = [];
let orgs = [];
RunnerTeamService.runnerTeamControllerGetAll().then((val) => {
teams = val;
});
RunnerOrganizationService.runnerOrganizationControllerGetAll().then((val) => {
orgs = val;
});
function focus(el) {
el.focus();
}
$: middlename_input_value = "";
$: phone_input_value = "";
$: email_input_value = "";
$: lastname_input_value = "";
$: firstname_input_value = "";
$: address_input1_value = "";
$: address_input2_value = "";
$: address_zipcode_value = "";
$: address_city_value = "";
$: processed_last_submit = true;
$: address_checked = true;
$: isPhoneValidOrEmpty =
(phone_input_value.includes("+") &&
isMobilePhone(
phone_input_value
.replaceAll("(", "")
.replaceAll(")", "")
.replaceAll("-", "")
.replaceAll(" ", "")
)) ||
phone_input_value === "";
$: isEmailValidOrEmpty =
isEmail(email_input_value) || email_input_value === "";
$: isLastnameValid = lastname_input_value.trim().length !== 0;
$: isFirstnameValid = firstname_input_value.trim().length !== 0;
$: isAddress1Valid = address_input1_value.trim().length !== 0;
$: iszipcodevalid = address_zipcode_value.trim().length !== 0;
$: iscityvalid = address_city_value.trim().length !== 0;
$: createbtnenabled =
isFirstnameValid &&
isLastnameValid &&
isEmailValidOrEmpty &&
isPhoneValidOrEmpty &&
((isAddress1Valid && iszipcodevalid && iscityvalid) ||
address_checked === false);
(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
})();
function submit() {
if (processed_last_submit === true) {
processed_last_submit = false;
toast.loading($_("contact-is-being-added"));
let address = {};
if (address_checked === true) {
address = {
address1: address_input1_value,
address2: address_input2_value || "",
postalcode: address_zipcode_value,
city: address_city_value,
country: "DE",
};
}
let postdata = {
groups: selected_team,
firstname: firstname_input_value,
lastname: lastname_input_value,
address,
};
if (middlename_input_value) {
postdata.middlename = middlename_input_value;
}
if (phone_input_value) {
postdata.phone = phone_input_value;
}
if (email_input_value) {
postdata.email = email_input_value;
}
GroupContactService.groupContactControllerPost(postdata)
.then((result) => {
firstname_input_value = "";
lastname_input_value = "";
middlename_input_value = "";
email_input_value = "";
modal_open = false;
//
toast.dismiss();
toast.success($_("contact-added"));
current_contacts.push(result);
current_contacts = current_contacts;
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
});
}
}
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-4 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M2 22a8 8 0 1 1 16 0H2zm8-9c-3.315 0-6-2.685-6-6s2.685-6 6-6 6 2.685 6 6-2.685 6-6 6zm10 4h4v2h-4v-2zm-3-5h7v2h-7v-2zm2-5h5v2h-5V7z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_("create-a-new-contact")}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_(
"please-provide-the-required-information-to-add-a-new-contact"
)}
</p>
</div>
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6">
<label
for="firstname"
class="block text-sm font-medium text-gray-700"
>{$_("first-name")}</label
>
<input
use:focus
autocomplete="off"
placeholder={$_("first-name")}
class:border-red-500={!isFirstnameValid}
class:focus:border-red-500={!isFirstnameValid}
class:focus:ring-red-500={!isFirstnameValid}
bind:value={firstname_input_value}
bind:this={firstname_input}
type="text"
name="firstname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isFirstnameValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("first-name-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="trackname"
class="block text-sm font-medium text-gray-700"
>{$_("middle-name")}</label
>
<input
autocomplete="off"
placeholder={$_("middle-name")}
bind:value={middlename_input_value}
bind:this={middlename_input}
type="text"
name="trackname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
</div>
<div class="col-span-6">
<label
for="lastname"
class="block text-sm font-medium text-gray-700"
>{$_("last-name")}</label
>
<input
autocomplete="off"
placeholder={$_("last-name")}
class:border-red-500={!isLastnameValid}
class:focus:border-red-500={!isLastnameValid}
class:focus:ring-red-500={!isLastnameValid}
bind:value={lastname_input_value}
bind:this={lastname_input}
type="text"
name="lastname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isLastnameValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("last-name-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="team"
class="block text-sm font-medium text-gray-700"
>{$_("teams")}</label
>
<select
name="team"
multiple
bind:value={selected_team}
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
>
{#each teams as team}
<option value={team.id}>
{team.parentGroup.name}
&gt;
{team.name}
</option>
{/each}
{#each orgs as org}
<option value={org.id}>{org.name}</option>
{/each}
</select>
</div>
<div class="col-span-6">
<label
for="phone"
class="block text-sm font-medium text-gray-700"
>{$_("phone")}</label
>
<input
autocomplete="off"
placeholder={$_("phone")}
class:border-red-500={!isPhoneValidOrEmpty}
class:focus:border-red-500={!isPhoneValidOrEmpty}
class:focus:ring-red-500={!isPhoneValidOrEmpty}
bind:value={phone_input_value}
bind:this={phone_input}
type="tel"
name="phone"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isPhoneValidOrEmpty}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{@html $_(
"the-provided-phone-number-is-invalid-less-than-br-greater-than-please-enter-a-valid-international-number"
)}
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="email"
class="block text-sm font-medium text-gray-700"
>{$_("e-mail-adress")}</label
>
<input
autocomplete="off"
placeholder={$_("e-mail-adress")}
class:border-red-500={!isEmailValidOrEmpty}
class:focus:border-red-500={!isEmailValidOrEmpty}
class:focus:ring-red-500={!isEmailValidOrEmpty}
bind:value={email_input_value}
bind:this={email_input}
type="email"
name="email"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isEmailValidOrEmpty}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-email-is-required")}
</span>
{/if}
</div>
<div class="flex items-start">
<div class="flex items-center h-5">
<input
bind:checked={address_checked}
id="comments"
name="comments"
type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
/>
</div>
<div class="ml-3 text-sm">
<label for="comments" class="font-semibold text-gray-700"
>{$_("address")}</label
>
</div>
</div>
{#if address_checked === true}
<div class="col-span-6">
<label
for="address1"
class="block text-sm font-medium text-gray-700"
>{$_("address")}</label
>
<input
autocomplete="off"
placeholder={$_("address")}
class:border-red-500={!isAddress1Valid}
class:focus:border-red-500={!isAddress1Valid}
class:focus:ring-red-500={!isAddress1Valid}
bind:value={address_input1_value}
bind:this={address_input1}
type="text"
name="address1"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isAddress1Valid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("address-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="address2"
class="block text-sm font-medium text-gray-700"
>{$_("apartment-suite-etc")}</label
>
<input
autocomplete="off"
placeholder={$_("apartment-suite-etc")}
bind:value={address_input2_value}
bind:this={address_input2}
type="text"
name="address2"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
</div>
<div class="col-span-6">
<label
for="zipcode"
class="block text-sm font-medium text-gray-700"
>{$_("zip-postal-code")}</label
>
<input
autocomplete="off"
placeholder={$_("zip-postal-code")}
class:border-red-500={!iszipcodevalid}
class:focus:border-red-500={!iszipcodevalid}
class:focus:ring-red-500={!iszipcodevalid}
bind:value={address_zipcode_value}
bind:this={address_zipcode}
type="text"
name="zipcode"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !iszipcodevalid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-zipcode-postal-code-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="city"
class="block text-sm font-medium text-gray-700"
>{$_("city")}</label
>
<input
autocomplete="off"
placeholder={$_("city")}
class:border-red-500={!iscityvalid}
class:focus:border-red-500={!iscityvalid}
class:focus:ring-red-500={!iscityvalid}
bind:value={address_city_value}
bind:this={address_city}
type="text"
name="city"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !iscityvalid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-city-is-required")}
</span>
{/if}
</div>
{/if}
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 grid gap-2 rounded-b">
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("create")}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}
@@ -0,0 +1,399 @@
<script>
import { _ } from "svelte-i18n";
import store from "../../store";
import {
GroupContactService,
RunnerTeamService,
RunnerOrganizationService,
} from "@odit/lfk-client-js";
import PromiseError from "../base/PromiseError.svelte";
import isEmail from "validator/es/lib/isEmail";
import toast from "svelte-french-toast";
let data_loaded = false;
let orgs = [];
let teams = [];
export let params;
$: delete_triggered = false;
$: original_data = {};
$: editable = {};
$: changes_performed = !(
JSON.stringify(original_data) === JSON.stringify(editable)
);
$: isEmailValid =
(editable.email || "") === "" ||
(editable.email && isEmail(editable.email || ""));
$: isFirstnameValid = editable.firstname !== "";
$: isLastnameValid = editable.lastname !== "";
$: save_enabled =
changes_performed &&
isFirstnameValid &&
isLastnameValid &&
isEmailValid &&
isPhoneValidOrEmpty &&
((isAddress1Valid && iszipcodevalid && iscityvalid) ||
editable.address_checked === false);
const promise = GroupContactService.groupContactControllerGetOne(
params.contact
).then((data) => {
data_loaded = true;
original_data = Object.assign(original_data, data);
editable = Object.assign(editable, original_data);
editable.groups = editable.groups.map((g) => g.id);
original_data.groups = original_data.groups.map((g) => g.id);
editable.address_checked = editable.address.address1 !== null;
original_data.address_checked = editable.address.address1 !== null;
if (editable.address_checked === false) {
editable.address = {
address1: "",
address2: "",
city: "",
postalcode: "",
country: "",
};
}
});
RunnerOrganizationService.runnerOrganizationControllerGetAll().then((val) => {
orgs = val;
});
RunnerTeamService.runnerTeamControllerGetAll().then((val) => {
teams = val;
});
$: isPhoneValidOrEmpty =
editable.phone?.includes("+") ||
editable.phone === "" ||
editable.phone === null;
$: isAddress1Valid = editable.address?.address1?.trim().length !== 0;
$: iszipcodevalid = editable.address?.postalcode?.trim().length !== 0;
$: iscityvalid = editable.address?.city?.trim().length !== 0;
function submit() {
if (data_loaded === true && save_enabled) {
toast.loading($_("contact-is-being-updated"));
editable.address.country = "DE";
if (editable.address_checked === false) {
editable.address = null;
}
if (editable.email) editable.email = editable.email;
if (editable.phone) editable.phone = editable.phone;
if (editable.middlename) editable.middlename = editable.middlename;
GroupContactService.groupContactControllerPut(original_data.id, editable)
.then((resp) => {
Object.assign(original_data, editable);
original_data = original_data;
toast.dismiss();
toast.success($_("updated-contact"));
})
.catch((err) => {});
} else {
}
}
function deleteContact() {
GroupContactService.groupContactControllerRemove(original_data.id, true)
.then((resp) => {
location.replace("./");
})
.catch((err) => {});
}
</script>
{#await promise}
{$_("loading-contact-details")}
{:then}
<section class="container p-5 select-none">
<div class="flex flex-row mb-4">
<div class="w-full">
<nav class="w-full flex">
<ol class="list-none flex flex-row items-center justify-start">
<li class="flex items-center">
<a class="mr-2" href="./"
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="inline-block"
><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg
>
{$_("contacts")}</a
>
</li>
</ol>
</nav>
</div>
</div>
<div class="mb-4 text-3xl font-extrabold leading-tight">
{original_data.firstname}
{original_data.middlename || ""}
{original_data.lastname}
<div data-id="contact_actions_${editable.id}">
{#if store.state.jwtinfo.userdetails.permissions.includes("CONTACT:DELETE")}
{#if delete_triggered}
<button
on:click={deleteContact}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm"
>{$_("confirm-deletion")}</button
>
<button
on:click={() => {
delete_triggered = !delete_triggered;
}}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm"
>{$_("cancel")}</button
>
{/if}
{#if !delete_triggered}
<button
on:click={() => {
delete_triggered = true;
}}
type="button"
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm"
>{$_("delete-contact")}</button
>
{/if}
{/if}
{#if !delete_triggered}
<button
disabled={!save_enabled}
class:opacity-50={!save_enabled}
type="button"
on:click={submit}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:w-auto sm:text-sm mb-1 lg:mb-0"
>{$_("save-changes")}</button
>
{/if}
</div>
</div>
<!-- -->
<div class="text-sm w-full mt-2">
<label for="firstname" class="font-semibold text-gray-700"
>{$_("first-name")}</label
>
<input
autocomplete="off"
placeholder={$_("first-name")}
type="text"
class:border-red-500={!isFirstnameValid}
class:focus:border-red-500={!isFirstnameValid}
class:focus:ring-red-500={!isFirstnameValid}
bind:value={editable.firstname}
name="firstname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isFirstnameValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("first-name-is-required")}
</span>
{/if}
</div>
<div class="text-sm w-full mt-2">
<label for="middlename" class="font-semibold text-gray-700"
>{$_("middle-name")}</label
>
<input
autocomplete="off"
placeholder={$_("middle-name")}
type="text"
bind:value={editable.middlename}
name="middlename"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
</div>
<div class="text-sm w-full mt-2">
<label for="lastname" class="font-semibold text-gray-700"
>{$_("last-name")}</label
>
<input
autocomplete="off"
placeholder={$_("last-name")}
type="text"
bind:value={editable.lastname}
class:border-red-500={!isLastnameValid}
class:focus:border-red-500={!isLastnameValid}
class:focus:ring-red-500={!isLastnameValid}
name="lastname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isLastnameValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("last-name-is-required")}
</span>
{/if}
</div>
<div class="text-sm w-full mt-2">
<label for="email" class="font-semibold text-gray-700"
>{$_("e-mail-adress")}</label
>
<input
autocomplete="off"
placeholder={$_("e-mail-adress")}
type="email"
bind:value={editable.email}
class:border-red-500={!isEmailValid}
class:focus:border-red-500={!isEmailValid}
class:focus:ring-red-500={!isEmailValid}
name="email"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isEmailValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-email-is-required")}
</span>
{/if}
</div>
<div class="text-sm w-full mt-2">
<label for="phone" class="font-semibold text-gray-700">{$_("phone")}</label>
<input
autocomplete="off"
placeholder={$_("phone")}
type="tel"
class:border-red-500={!isPhoneValidOrEmpty}
class:focus:border-red-500={!isPhoneValidOrEmpty}
class:focus:ring-red-500={!isPhoneValidOrEmpty}
bind:value={editable.phone}
name="phone"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isPhoneValidOrEmpty}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-international-phone-number-is-required")}
</span>
{/if}
</div>
<div class="text-sm w-full mt-2">
<span class="font-semibold text-gray-700">{$_("groups")}</span>
<select
bind:value={editable.groups}
name="team"
multiple
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
>
{#each teams as team}
<option value={team.id}>
{team.parentGroup.name}
&gt;
{team.name}
</option>
{/each}
{#each orgs as org}
<option value={org.id}>{org.name}</option>
{/each}
</select>
</div>
<!-- -->
<div class="flex items-start mt-2">
<div class="flex items-center h-5">
<input
bind:checked={editable.address_checked}
id="comments"
name="comments"
type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
/>
</div>
<div class="ml-3 text-sm">
<label for="comments" class="font-semibold text-gray-700"
>{$_("address")}</label
>
</div>
</div>
{#if editable.address_checked === true}
<div class="col-span-6">
<label for="address1" class="block text-sm font-medium text-gray-700"
>{$_("address")}</label
>
<input
autocomplete="off"
placeholder="Address"
class:border-red-500={!isAddress1Valid}
class:focus:border-red-500={!isAddress1Valid}
class:focus:ring-red-500={!isAddress1Valid}
bind:value={editable.address.address1}
type="text"
name="address1"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isAddress1Valid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("address-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label for="address2" class="block text-sm font-medium text-gray-700"
>{$_("apartment-suite-etc")}</label
>
<input
autocomplete="off"
placeholder={$_("apartment-suite-etc")}
bind:value={editable.address.address2}
type="text"
name="address2"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
</div>
<div class="col-span-6">
<label for="zipcode" class="block text-sm font-medium text-gray-700"
>{$_("zip-postal-code")}</label
>
<input
autocomplete="off"
placeholder={$_("zip-postal-code")}
class:border-red-500={!iszipcodevalid}
class:focus:border-red-500={!iszipcodevalid}
class:focus:ring-red-500={!iszipcodevalid}
bind:value={editable.address.postalcode}
type="text"
name="zipcode"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !iszipcodevalid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-zipcode-postal-code-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label for="city" class="block text-sm font-medium text-gray-700"
>{$_("city")}</label
>
<input
autocomplete="off"
placeholder={$_("city")}
class:border-red-500={!iscityvalid}
class:focus:border-red-500={!iscityvalid}
class:focus:ring-red-500={!iscityvalid}
bind:value={editable.address.city}
type="text"
name="city"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !iscityvalid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-city-is-required")}
</span>
{/if}
</div>
{/if}
</section>
{:catch error}
<PromiseError {error} />
{/await}
+30
View File
@@ -0,0 +1,30 @@
<script>
import { _ } from "svelte-i18n";
import store from "../../store";
import AddContactModal from "./AddContactModal.svelte";
import ContactsOverview from "./ContactsOverview.svelte";
export let modal_open = false;
let current_contacts = [];
</script>
<section class="container p-5">
<h4 class="mb-1 text-3xl font-extrabold leading-tight">
{$_("contacts")}
</h4>
{#if store.state.jwtinfo.userdetails.permissions.includes("CONTACT:CREATE")}
<button
on:click={() => {
modal_open = true;
}}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:w-auto sm:text-sm"
>
{$_("create-a-new-contact")}
</button>
{/if}
<ContactsOverview bind:current_contacts />
</section>
{#if store.state.jwtinfo.userdetails.permissions.includes("CONTACT:CREATE")}
<AddContactModal bind:current_contacts bind:modal_open />
{/if}
@@ -0,0 +1,17 @@
<script>
import { _ } from "svelte-i18n";
import AddContactModal from "./AddContactModal.svelte";
import team_empty from "../teams/team_empty.svg";
let modal_open = false;
let current_contacts = [];
</script>
<div class="text-center items-center justify-center">
<p class="mb-16 text-lg text-gray-500">
<img class="w-full h-44" src={team_empty} alt="" />
<span class="font-bold">{$_("there-are-no-contacts-added-yet")}</span><br />
<span>{$_("add-your-first-contact")}</span>
</p>
</div>
<AddContactModal bind:modal_open bind:current_contacts />
@@ -0,0 +1,198 @@
<script>
import { _ } from "svelte-i18n";
import { GroupContactService } from "@odit/lfk-client-js";
const promise = GroupContactService.groupContactControllerGetAll().then(
(result) => {
current_contacts = result;
}
);
import store from "../../store";
import ContactsEmptyState from "./ContactsEmptyState.svelte";
import toast from "svelte-french-toast";
$: searchvalue = "";
$: active_deletes = [];
export let current_contacts = [];
</script>
{#if store.state.jwtinfo.userdetails.permissions.includes("TEAM:GET")}
{#await promise}
<div
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
role="alert"
>
<p class="font-bold">{$_("contacts-are-being-loaded")}</p>
<p class="text-sm">{$_("this-might-take-a-moment")}</p>
</div>
{:then}
{#if current_contacts.length === 0}
<ContactsEmptyState />
{:else}
<input
type="search"
bind:value={searchvalue}
placeholder={$_("datatable.search")}
aria-label={$_("datatable.search")}
class="mb-2 w-full sm:w-auto mt-1 sm:mt-0 p-2 rounded-md border"
/>
<div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"
>
<table class="divide-y divide-gray-200 w-full">
<thead class="bg-gray-50">
<tr class="odd:bg-white even:bg-gray-100">
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
{$_("name")}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
{$_("groups")}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
{$_("address")}
</th>
<th scope="col" class="relative px-6 py-3">
<span class="sr-only">{$_("action")}</span>
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
{#each current_contacts as t}
{#if Object.values(t)
.toString()
.toLowerCase()
.includes(searchvalue)}
<tr
class="odd:bg-white even:bg-gray-100"
data-rowid="team_{t.id}"
>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">
{t.firstname}
{t.middlename || ""}
{t.lastname}
</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div
class="text-sm font-medium text-gray-900 gap-0.5 flex flex-wrap"
>
{#if t.groups.length > 0}
{#each t.groups as g}
{#if g.responseType === "RUNNERORGANIZATION"}
<a
href="../orgs/{g.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800 border border-current"
>{g.name}</a
>
{:else}
<a
href="../teams/{g.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800 border border-current"
>{g.parentGroup.name}
&gt;
{g.name}</a
>
{/if}
{/each}
{:else}
{$_("contact-is-not-a-member-in-any-group")}
{/if}
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">
{#if t.address.address1 !== null}
{t.address.address1}<br />
{t.address.address2 || ""}<br />
{t.address.postalcode}
{t.address.city}
{t.address.country}
{/if}
</div>
</div>
</div>
</td>
{#if active_deletes[t.id] === true}
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"
>
<button
on:click={() => {
active_deletes[t.id] = false;
}}
tabindex="0"
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer"
>{$_("cancel-delete")}</button
>
<button
on:click={() => {
toast.loading($_("deleting-contact"));
GroupContactService.groupContactControllerRemove(
t.id,
false
).then((resp) => {
current_contacts = current_contacts.filter(
(obj) => obj.id !== t.id
);
toast.dismiss();
toast.success($_("contact-deleted"));
});
}}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
>{$_("confirm-delete")}</button
>
</td>
{:else}
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"
>
<a
href="./{t.id}"
class="text-indigo-600 hover:text-indigo-900"
>{$_("details")}</a
>
{#if store.state.jwtinfo.userdetails.permissions.includes("TEAM:DELETE")}
<button
on:click={() => {
active_deletes[t.id] = true;
}}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
>{$_("delete")}</button
>
{/if}
</td>
{/if}
</tr>
{/if}
{/each}
</tbody>
</table>
</div>
{/if}
{:catch error}
<div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500">
<span class="inline-block align-middle mr-8">
<b class="capitalize">{$_("general_promise_error")}</b>
{error}
</span>
</div>
{/await}
{/if}
+439
View File
@@ -0,0 +1,439 @@
<script>
import { _ } from "svelte-i18n";
import localForage from "localforage";
import store from "../../store";
import { router } from "tinro";
import NoComponentLoaded from "../base/NoComponentLoaded.svelte";
import { AuthService } from "@odit/lfk-client-js";
import { Toaster } from "svelte-french-toast";
$: navOpen = false;
function logout() {
localForage.clear();
location.replace("/");
}
</script>
<section class="min-h-screen bg-gray-50">
<div
class:collapsed_navigation={!navOpen}
style="z-index:2;"
class="select-none fixed top-0 left-0 h-full pb-10 overflow-x-hidden overflow-y-auto transition origin-left transform border-r w-60 bg-gray-50"
>
<a href="/" class="flex items-center px-4 py-5">
<img src="/lfk-logo.png" alt="Logo" class="h-10" />
<h3 class="text-lg font-bold">LfK!Admin</h3>
</a>
<nav class="text-sm font-medium text-gray-600" aria-label="Main Navigation">
<a
class:activenav={$router.path === "/"}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z"
/>
</svg>
<span>{$_("dashboard-title")}</span>
</a>
{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:GET")}
<a
class:activenav={$router.path.includes("/runners/")}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/runners/"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M9.83 8.79L8 9.456V13H6V8.05h.015l5.268-1.918c.244-.093.51-.14.782-.131a2.616 2.616 0 0 1 2.427 1.82c.186.583.356.977.51 1.182A4.992 4.992 0 0 0 19 11v2a6.986 6.986 0 0 1-5.402-2.547l-.581 3.297L15 15.67V23h-2v-5.986l-2.05-1.987-.947 4.298-6.894-1.215.348-1.97 4.924.868L9.83 8.79zM13.5 5.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"
/></svg
>
<span>{$_("runners")}</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("TEAM:GET")}
<a
class:activenav={$router.path.includes("/teams/")}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/teams/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 640 512"
><path
fill="currentColor"
d="M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z"
/></svg
>
<span>{$_("teams")}</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("ORGANIZATION:GET")}
<a
class:activenav={$router.path.includes("/orgs/")}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/orgs/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M17 19h2v-8h-6v8h2v-6h2v6zM3 19V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v5h2v10h1v2H2v-2h1zm4-8v2h2v-2H7zm0 4v2h2v-2H7zm0-8v2h2V7H7z"
/></svg
>
<span>{$_("orgs")}</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:GET")}
<a
class:activenav={$router.path.includes("/donors/")}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/donors/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M9.33 11.5h2.17A4.5 4.5 0 0 1 16 16H8.999L9 17h8v-1a5.578 5.578 0 0 0-.886-3H19a5 5 0 0 1 4.516 2.851C21.151 18.972 17.322 21 13 21c-2.761 0-5.1-.59-7-1.625L6 10.071A6.967 6.967 0 0 1 9.33 11.5zM5 19a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v9zM18 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm-7-3a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"
/></svg
>
<span>{$_("donors")}</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:GET")}
<a
class:activenav={$router.path.includes("/donations/")}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/donations/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z"
/></svg
>
<span>{$_("donations")}</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("TRACK:GET")}
<a
class:activenav={$router.path === "/tracks/"}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/tracks/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 640 512"
><path
fill="currentColor"
d="M635.7 167.2L556.1 31.7c-8.8-15-28.3-20.1-43.5-11.5l-69 39.1L503.3 161c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L416 75l-55.2 31.3 27.9 47.4c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L333.2 122 278 153.3 337.8 255c2.2 3.7.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9l-59.7-101.7-55.2 31.3 27.9 47.4c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9l-27.9-47.5-55.2 31.3 59.7 101.7c2.2 3.7.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L84.9 262.9l-69 39.1C.7 310.7-4.6 329.8 4.2 344.8l79.6 135.6c8.8 15 28.3 20.1 43.5 11.5L624.1 210c15.2-8.6 20.4-27.8 11.6-42.8z"
/></svg
>
<span>{$_("tracks")}</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:GET")}
<a
class:activenav={$router.path === "/cards/"}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/cards/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z"
/></svg
>
<span>{$_("cards")}</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:GET")}
<a
class:activenav={$router.path.includes("/scans/")}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/scans/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
><path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M2 4h2v16H2V4zm4 0h1v16H6V4zm2 0h2v16H8V4zm3 0h2v16h-2V4zm3 0h2v16h-2V4zm3 0h1v16h-1V4zm2 0h3v16h-3V4z"
/></svg
>
<span>Scans</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("CONTACT:GET")}
<a
class:activenav={$router.path.includes("/contacts/")}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/contacts/"
>
<svg
fill="currentColor"
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M2 22a8 8 0 1 1 16 0H2zm8-9c-3.315 0-6-2.685-6-6s2.685-6 6-6 6 2.685 6 6-2.685 6-6 6zm10 4h4v2h-4v-2zm-3-5h7v2h-7v-2zm2-5h5v2h-5V7z"
/></svg
>
<span>{$_("contacts")}</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("STATION:GET")}
<a
class:activenav={$router.path.includes("/scanstations/")}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/scanstations/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
><path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z"
/></svg
>
<span>{$_("scanstations")}</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("STATSCLIENT:GET")}
<a
class:activenav={$router.path.includes("/statsclients/")}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/statsclients/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
><path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z"
/></svg
>
<span>{$_("statsclients")}</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("USER:GET")}
<a
class:activenav={$router.path.includes("/users/")}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/users/"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
viewBox="0 0 24 24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M12 14v8H4a8 8 0 018-8zm0-1a6 6 0 110-12 6 6 0 010 12zm2.6 5.81a3.51 3.51 0 010-1.62l-1-.57 1-1.74 1 .58a3.5 3.5 0 011.4-.82V13.5h2v1.15a3.5 3.5 0 011.4.8l1-.57 1 1.74-1 .57a3.51 3.51 0 010 1.62l1 .57-1 1.74-1-.58a3.5 3.5 0 01-1.4.82v1.14h-2v-1.15a3.5 3.5 0 01-1.4-.8l-1 .57-1-1.74 1-.57zM18 17a1 1 0 100 2 1 1 0 000-2z"
/></svg
>
<span>{$_("users")}</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("USERGROUP:GET")}
<a
class:activenav={$router.path.includes("/groups/")}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/groups/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 640 512"
><path
fill="currentColor"
d="M610.5 341.3c2.6-14.1 2.6-28.5 0-42.6l25.8-14.9c3-1.7 4.3-5.2 3.3-8.5-6.7-21.6-18.2-41.2-33.2-57.4-2.3-2.5-6-3.1-9-1.4l-25.8 14.9c-10.9-9.3-23.4-16.5-36.9-21.3v-29.8c0-3.4-2.4-6.4-5.7-7.1-22.3-5-45-4.8-66.2 0-3.3.7-5.7 3.7-5.7 7.1v29.8c-13.5 4.8-26 12-36.9 21.3l-25.8-14.9c-2.9-1.7-6.7-1.1-9 1.4-15 16.2-26.5 35.8-33.2 57.4-1 3.3.4 6.8 3.3 8.5l25.8 14.9c-2.6 14.1-2.6 28.5 0 42.6l-25.8 14.9c-3 1.7-4.3 5.2-3.3 8.5 6.7 21.6 18.2 41.1 33.2 57.4 2.3 2.5 6 3.1 9 1.4l25.8-14.9c10.9 9.3 23.4 16.5 36.9 21.3v29.8c0 3.4 2.4 6.4 5.7 7.1 22.3 5 45 4.8 66.2 0 3.3-.7 5.7-3.7 5.7-7.1v-29.8c13.5-4.8 26-12 36.9-21.3l25.8 14.9c2.9 1.7 6.7 1.1 9-1.4 15-16.2 26.5-35.8 33.2-57.4 1-3.3-.4-6.8-3.3-8.5l-25.8-14.9zM496 368.5c-26.8 0-48.5-21.8-48.5-48.5s21.8-48.5 48.5-48.5 48.5 21.8 48.5 48.5-21.7 48.5-48.5 48.5zM96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm224 32c1.9 0 3.7-.5 5.6-.6 8.3-21.7 20.5-42.1 36.3-59.2 7.4-8 17.9-12.6 28.9-12.6 6.9 0 13.7 1.8 19.6 5.3l7.9 4.6c.8-.5 1.6-.9 2.4-1.4 7-14.6 11.2-30.8 11.2-48 0-61.9-50.1-112-112-112S208 82.1 208 144c0 61.9 50.1 112 112 112zm105.2 194.5c-2.3-1.2-4.6-2.6-6.8-3.9-8.2 4.8-15.3 9.8-27.5 9.8-10.9 0-21.4-4.6-28.9-12.6-18.3-19.8-32.3-43.9-40.2-69.6-10.7-34.5 24.9-49.7 25.8-50.3-.1-2.6-.1-5.2 0-7.8l-7.9-4.6c-3.8-2.2-7-5-9.8-8.1-3.3.2-6.5.6-9.8.6-24.6 0-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h255.4c-3.7-6-6.2-12.8-6.2-20.3v-9.2zM173.1 274.6C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z"
/></svg
>
<span>{$_("user-groups")}</span>
</a>
{/if}
<a
class:activenav={$router.path === "/settings/"}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/settings/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fill-rule="evenodd"
d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z"
clip-rule="evenodd"
/>
</svg>
<span>{$_("settings")}</span>
</a>
<a
class:activenav={$router.path === "/about/"}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
href="/about/"
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
xmlns="http://www.w3.org/2000/svg"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
viewBox="0 0 24 24"
><circle cx="12" cy="12" r="10" />
<path d="M12 16v-4M12 8h.01" /></svg
>
<span>{$_("about")}</span>
</a>
<button
tabindex="0"
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
on:click={() => {
AuthService.authControllerLogout();
logout();
}}
>
<svg
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2a9.985 9.985 0 0 1 8 4h-2.71a8 8 0 1 0 .001 12h2.71A9.985 9.985 0 0 1 12 22zm7-6v-3h-8v-2h8V8l5 4-5 4z"
/></svg
>
<span>{$_("logout")}</span>
</button>
</nav>
</div>
<div class="ml-0 transition md:ml-60">
<header
class="flex items-center w-full px-4 bg-white border-b h-14 md:hidden"
>
<button
on:click={() => {
navOpen = true;
}}
class="block btn btn-light md:hidden"
>
<span class="sr-only">Menu</span><svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="size-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
/>
</svg>
</button>
<span class="inline-block">
<img src="/lfk-logo.png" alt="Logo" class="h-8 inline-block" />
<span class="text-lg font-bold">LfK!Admin</span>
</span>
</header>
<Toaster position="top-right" />
<slot>
<NoComponentLoaded />
</slot>
</div>
{#if navOpen === true}
<button
on:click={() => {
navOpen = false;
}}
class:hidden={!navOpen}
class="fixed inset-0 z-10 w-screen h-screen bg-black bg-opacity-25 md:hidden"
/>
{/if}
</section>
<style>
.collapsed_navigation {
transform: translateX(-100%);
}
@media (min-width: 768px) {
.collapsed_navigation {
transform: translateX(0px);
}
}
</style>
@@ -0,0 +1,228 @@
<script>
import { _ } from "svelte-i18n";
import { StatsService } from "@odit/lfk-client-js";
import store from "../../store";
import StatCard from "./StatCard.svelte";
const stats_promise = StatsService.statsControllerGet();
</script>
<div class="p-2 md:p-5 overflow-x-hidden">
<h4 class="mb-1 text-3xl font-extrabold leading-tight">
{$_("dashboard-greeting")} <span class="text-blue-500"
>{store.state.jwtinfo.userdetails.firstname}
{store.state.jwtinfo.userdetails.lastname}</span
>
</h4>
{#await stats_promise}
<div
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
role="alert"
>
<p class="font-bold">{$_("stats-are-being-loaded")}</p>
<p class="text-sm">{$_("this-might-take-a-moment")}</p>
</div>
{:then stats}
<div
class="grid gap-1 grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 2xl:grid-cols-6 sm:gap-4"
>
<StatCard
title={$_("runners")}
value={stats.total_runners}
href="/runners/"
>
<svg
height="24"
width="24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
><path d="M0 0h24v24H0z" fill="none" />
<path
d="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1 2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1l-5.2 2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z"
/></svg
>
</StatCard>
<StatCard
title={$_("total-scans")}
value={stats.total_scans}
href="/scans/"
>
<svg
fill="currentColor"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
><path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M2 4h2v16H2V4zm4 0h1v16H6V4zm2 0h2v16H8V4zm3 0h2v16h-2V4zm3 0h2v16h-2V4zm3 0h1v16h-1V4zm2 0h3v16h-3V4z"
/></svg
>
</StatCard>
<StatCard
title={$_("total-donors")}
value={stats.total_donors}
href="/donors/"
>
<svg
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M9.33 11.5h2.17A4.5 4.5 0 0 1 16 16H8.999L9 17h8v-1a5.578 5.578 0 0 0-.886-3H19a5 5 0 0 1 4.516 2.851C21.151 18.972 17.322 21 13 21c-2.761 0-5.1-.59-7-1.625L6 10.071A6.967 6.967 0 0 1 9.33 11.5zM5 19a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v9zM18 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm-7-3a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"
/></svg
>
</StatCard>
<StatCard
title={$_("total-donation-count")}
value={stats.total_donations}
href="/donations/"
>
<svg
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z"
/></svg
>
</StatCard>
<StatCard
title={$_("average-donation")}
value={`${parseFloat(stats.average_donation / 100).toLocaleString(
undefined,
{
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}
)}`}
href="/donations/"
>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24"
fill="currentColor"
width="24"
><path d="M0 0h24v24H0z" fill="none" />
<path
d="M15 18.5A6.48 6.48 0 019.24 15H15v-2H8.58c-.05-.33-.08-.66-.08-1s.03-.67.08-1H15V9H9.24A6.491 6.491 0 0115 5.5c1.61 0 3.09.59 4.23 1.57L21 5.3A8.955 8.955 0 0015 3c-3.92 0-7.24 2.51-8.48 6H3v2h3.06a8.262 8.262 0 000 2H3v2h3.52c1.24 3.49 4.56 6 8.48 6 2.31 0 4.41-.87 6-2.3l-1.78-1.77c-1.13.98-2.6 1.57-4.22 1.57z"
/></svg
>
</StatCard>
<StatCard
title={$_("total-donations")}
value={`${parseFloat(stats.total_donation / 100).toLocaleString(
undefined,
{
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}
)}`}
href="/donations/"
>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24"
fill="currentColor"
width="24"
><path d="M0 0h24v24H0z" fill="none" />
<path
d="M15 18.5A6.48 6.48 0 019.24 15H15v-2H8.58c-.05-.33-.08-.66-.08-1s.03-.67.08-1H15V9H9.24A6.491 6.491 0 0115 5.5c1.61 0 3.09.59 4.23 1.57L21 5.3A8.955 8.955 0 0015 3c-3.92 0-7.24 2.51-8.48 6H3v2h3.06a8.262 8.262 0 000 2H3v2h3.52c1.24 3.49 4.56 6 8.48 6 2.31 0 4.41-.87 6-2.3l-1.78-1.77c-1.13.98-2.6 1.57-4.22 1.57z"
/></svg
>
</StatCard>
<StatCard
title={$_("total-distance")}
value={`${stats.total_distance / 1000}km`}
href="/scans/"
>
<svg
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
height="24"
width="24"
><path d="M0 0h24v24H0z" fill="none" />
<path
d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 10H3V8h2v4h2V8h2v4h2V8h2v4h2V8h2v4h2V8h2v8z"
/></svg
>
</StatCard>
<StatCard
title={$_("average-distance")}
value={`${parseFloat(stats.average_distance / 1000).toLocaleString(
undefined,
{
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}
)}km`}
href="/scans/"
>
<svg
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
height="24"
width="24"
><path d="M0 0h24v24H0z" fill="none" />
<path
d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 10H3V8h2v4h2V8h2v4h2V8h2v4h2V8h2v4h2V8h2v8z"
/></svg
>
</StatCard>
<StatCard
title={$_("count_teams")}
value={stats.total_teams}
href="/teams/"
>
<svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
size="24"
class="stroke-current text-grey-500"
height="24"
width="24"
xmlns="http://www.w3.org/2000/svg"
><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
<circle cx="9" cy="7" r="4" />
<path d="M23 21v-2a4 4 0 0 0-3-3.87" />
<path d="M16 3.13a4 4 0 0 1 0 7.75" /></svg
>
</StatCard>
<StatCard
title={$_("count_organizations")}
value={stats.total_orgs}
href="/orgs/"
>
<svg
height="24"
fill="currentColor"
width="24"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M17 11V3H7v4H3v14h8v-4h2v4h8V11h-4zM7 19H5v-2h2v2zm0-4H5v-2h2v2zm0-4H5V9h2v2zm4 4H9v-2h2v2zm0-4H9V9h2v2zm0-4H9V5h2v2zm4 8h-2v-2h2v2zm0-4h-2V9h2v2zm0-4h-2V5h2v2zm4 12h-2v-2h2v2zm0-4h-2v-2h2v2z"
/></svg
>
</StatCard>
</div>
{:catch error}
<div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500">
<span class="inline-block align-middle mr-8">
<b class="capitalize">{$_("general_promise_error")}</b>
{error}
</span>
</div>
{/await}
</div>
+21
View File
@@ -0,0 +1,21 @@
<script>
import { _ } from "svelte-i18n";
export let href = "#";
export let title = "";
export let value = "";
</script>
<a {href}>
<div class="p-3 py-4 sm:p-4 rounded-lg bg-white border border-grey-100">
<div class="flex flex-row items-center justify-between">
<div class="flex flex-col">
<div class="text-md sm:text-xs uppercase font-normal text-grey-500">
{title}
</div>
<div class="text-2xl sm:text-xl font-bold font-mono">{value}</div>
</div>
<slot />
</div>
</div>
</a>
-24
View File
@@ -1,24 +0,0 @@
export function getlang(langkeys) {
return {
search: {
placeholder: langkeys.search
},
sort: {
sortAsc: langkeys.sort_column_ascending,
sortDesc: langkeys.sort_column_descending
},
pagination: {
previous: langkeys.previous,
next: langkeys.next,
navigate: (page, pages) => `${langkeys.page} ${page} ${langkeys.of} ${pages}`,
page: (page) => `${langkeys.page} ${page}`,
showing: langkeys.showing,
of: langkeys.of,
to: langkeys.to,
results: langkeys.records
},
loading: langkeys.loading,
noRecordsFound: langkeys.no_matching_records_found,
error: langkeys.an_error_happened_while_fetching_the_data
};
}
@@ -0,0 +1,340 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import {
DonationService,
DonorService,
RunnerService,
} from "@odit/lfk-client-js";
import Select from "svelte-select";
import { createEventDispatcher, onMount } from "svelte";
import toast from "svelte-french-toast";
export let modal_open;
const dispatch = createEventDispatcher();
const getDonorLabel = (option) =>
option.firstname + " " + (option.middlename || "") + " " + option.lastname;
const filterDonors = (label, filterText, option) =>
label.toLowerCase().includes(filterText.toLowerCase()) ||
option.value.id.toString().startsWith(filterText.toLowerCase());
$: donor = 0;
$: runner = 0;
$: donors = [];
$: runners = [];
$: is_fixed = false;
$: is_paid = false;
$: amount_input = 0;
$: processed_last_submit = true;
$: is_amount_valid = amount_input > 0;
$: createbtnenabled = is_amount_valid;
(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
})();
function submit() {
if (processed_last_submit === true) {
let amount_cent = Math.floor(amount_input * 100);
processed_last_submit = false;
toast.loading($_("adding-donation"));
if (is_fixed) {
let postdata = {
donor,
amount: amount_cent,
paidAmount: 0,
};
if (is_paid) {
postdata.paidAmount = amount_cent;
}
DonationService.donationControllerPostFixed(postdata)
.then((result) => {
donor = donors[0].id || 0;
runner = runners[0].id || 0;
amount_input = 0;
modal_open = false;
//
toast.dismiss();
toast.success($_("donation_added"));
dispatch("created", { donations: [result] });
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
});
} else {
let postdata = {
donor,
runner,
amountPerDistance: amount_cent,
};
DonationService.donationControllerPostDistance(postdata)
.then((result) => {
donor = donors[0].id || 0;
runner = runners[0].id || 0;
amount_input = 0;
modal_open = false;
//
toast.dismiss();
toast.success($_("donation_added"));
dispatch("created", { donations: [result] });
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
});
}
}
}
onMount(async () => {
donors = (await DonorService.donorControllerGetAll()).map(
(r) => {
return { label: getDonorLabel(r), value: r };
}
);
runners = (await RunnerService.runnerControllerGetAll()).map(
(r) => {
return { label: getDonorLabel(r), value: r };
}
);
});
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-4 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-md text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{#if is_fixed}
{$_("create-a-new-fixed-donation")}
{:else}{$_("create-a-new-distance-donation")}{/if}
</h3>
<label class="content-center align-middle object-center">
<span class="ml-2 text-base" class:text-gray-300={is_fixed}
>{$_("distance-donation")}</span
>
<input
class="toggle relative w-10 h-5 transition-all duration-200 ease-in-out bg-gray-400 rounded-full shadow-inner outline-none appearance-none align-middle"
type="checkbox"
bind:checked={is_fixed}
/>
<span class="ml-2 text-base" class:text-gray-300={!is_fixed}
>{$_("fixed-donation")}</span
>
</label>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_(
"please-provide-the-nessecary-information-to-create-a-new-donation"
)}
</p>
</div>
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6">
<label
for="donor"
class="block text-sm font-medium text-gray-700"
>{$_("donor")}</label
>
<Select
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
itemFilter={(label, filterText, option) =>
filterDonors(label, filterText, option)}
items={donors}
showChevron={true}
placeholder={$_("search-for-donor-name-or-id")}
noOptionsMessage={$_("no-donors-found")}
on:select={(selectedValue) =>
(donor = selectedValue.detail.value.id)}
on:clear={() => (donors = null)}
/>
</div>
{#if !is_fixed}
<div class="col-span-6">
<label
for="donor"
class="block text-sm font-medium text-gray-700"
>{$_("runner")}</label
>
<Select
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
itemFilter={(label, filterText, option) =>
filterDonors(label, filterText, option)}
items={runners}
showChevron={true}
placeholder={$_("search-for-runner-by-name-or-id")}
noOptionsMessage={$_("no-runners-found")}
on:select={(selectedValue) =>
(runner = selectedValue.detail.value.id)}
on:clear={() => (runner = null)}
/>
</div>
{/if}
<div class="col-span-6">
<label
for="donation_amount_eur"
class="block text-sm font-medium text-gray-700"
>
{#if !is_fixed}
{$_("amount-per-kilometer")}
{:else}{$_("donation-amount")}{/if}</label
>
<div class="mt-1 flex rounded-md shadow-sm">
<input
autocomplete="off"
class:border-red-500={!is_amount_valid}
class:focus:border-red-500={!is_amount_valid}
class:focus:ring-red-500={!is_amount_valid}
bind:value={amount_input}
type="number"
step="0.01"
name="donation_amount_eur"
class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 p-2"
placeholder="2.00"
/>
<span
class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm"
>€</span
>
</div>
{#if !is_amount_valid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("donation-amount-must-be-greater-that-0-00eur")}
</span>
{/if}
</div>
{#if is_fixed}
<div class="col-span-6">
<label
for="paid"
class="block text-sm font-medium text-gray-700"
>{$_("already-paid")}</label
>
<p class="text-gray-500">
<input
id="paid"
bind:checked={is_paid}
name="paid"
type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
/>
<span class="align-text-bottom">
{#if is_paid}
{$_("paid")}
{:else}
{$_("open")}
{/if}
</span>
</p>
</div>
{/if}
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 grid gap-2 rounded-b">
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("create")}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}
<style>
.toggle:before {
content: "";
position: absolute;
width: 1.25rem;
height: 1.25rem;
border-radius: 50%;
top: 0;
left: 0;
transform: scale(1.1);
box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.2);
background-color: white;
transition: 0.2s ease-in-out;
}
.toggle:checked {
/* @apply: bg-indigo-400; */
background-color: #7f9cf5;
}
.toggle:checked:before {
left: 1.25rem;
}
</style>
@@ -0,0 +1,205 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { DonationService } from "@odit/lfk-client-js";
import { createEventDispatcher } from "svelte";
import toast from "svelte-french-toast";
export let payment_modal_open = false;
export let original_data = {};
export let paid_amount_input = 0;
const dispatch = createEventDispatcher();
$: processed_last_submit = true;
$: createbtnenabled =
is_paid_amount_valid &&
!(paid_amount_input * 100 == original_data.paidAmount);
$: is_paid_amount_valid = paid_amount_input > 0;
(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
payment_modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
})();
function submit() {
if (processed_last_submit === true) {
processed_last_submit = false;
toast.loading($_("updating-donation"));
const editable = Object.assign({}, original_data);
editable.donor = editable.donor.id;
editable.paidAmount = Math.round(paid_amount_input * 100);
if (editable.responseType == "DISTANCEDONATION" || editable.runner) {
editable.runner = editable.runner.id;
DonationService.donationControllerPutDistance(
original_data.id,
editable
)
.then((result) => {
payment_modal_open = false;
//
toast.dismiss();
toast.success($_("donation-updated"));
dispatch("created", { donation: result });
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
});
} else {
DonationService.donationControllerPutFixed(original_data.id, editable)
.then((result) => {
payment_modal_open = false;
//
toast.dismiss();
toast.success($_("donation-updated"));
dispatch("created", { donation: result });
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
});
}
}
}
</script>
{#if payment_modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
payment_modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-4 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-md text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_("enter-payment")}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_(
"you-can-enter-the-donations-paid-amount-manually-or-use-the-max-button-to-use-the-donations-exact-amount"
)}
</p>
</div>
<div class="grid grid-cols gap-6">
<div class="w-full">
<label
for="token"
class="block text-sm font-medium text-gray-700"
>{$_("paid-amount")}</label
>
<div
class="inline-flex border-gray-300 border rounded-l-md rounded-r-md bg-gray-50 text-gray-500 w-full"
>
<input
autocomplete="off"
class:border-red-500={!is_paid_amount_valid}
class:focus:border-red-500={!is_paid_amount_valid}
class:focus:ring-red-500={!is_paid_amount_valid}
bind:value={paid_amount_input}
type="number"
step="0.01"
name="donation_amount_eur"
class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm p-2"
placeholder="2.00"
/>
<button
on:click={() => {
paid_amount_input = paid_amount_input = (
original_data.amount / 100
).toFixed(2);
}}
class="inline-flex items-center p-r-2 text-indigo-300 hover:text-indigo-700 text-sm"
>MAX</button
>
<span
class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm"
>€</span
>
</div>
{#if !is_paid_amount_valid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("payment-amount-must-be-greater-than-0-00eur")}
</span>
{/if}
</div>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 grid gap-2 rounded-b">
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("save-changes")}
</button>
<button
on:click={() => {
payment_modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}
@@ -0,0 +1,117 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { createEventDispatcher, onMount } from "svelte";
export let modal_open;
export let delete_donation = {
id: 0,
runner: {
firstname: "",
lastname: "",
},
donor: {
firstname: "",
lastname: "",
},
};
const dispatch = createEventDispatcher();
onMount(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
});
async function submit() {
dispatch("delete", { id: delete_donation.id });
modal_open = false;
}
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-4 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-md text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_("please-confirm-the-deletion-of-donation")}
</h3>
<div class="w-full">
<span class="inline-block"
><b>{$_("donor")}</b>: {delete_donation.donor.firstname}
{delete_donation.donor.lastname}</span
>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 grid gap-2 rounded-b">
<button
on:click={submit}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("delete")}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}
@@ -0,0 +1,352 @@
<script>
import { _ } from "svelte-i18n";
import store from "../../store";
import {
DonationService,
DonorService,
RunnerService,
} from "@odit/lfk-client-js";
import toast from "svelte-french-toast";
import PromiseError from "../base/PromiseError.svelte";
import Select from "svelte-select";
let data_loaded = false;
export let params;
$: delete_triggered = false;
$: original_data = {};
$: editable = {};
$: donor = {};
$: runner = {};
$: current_donors = [];
$: current_runners = [];
$: amount_input = 0;
$: is_amount_valid = amount_input > 0;
$: paid_amount_input = 0;
$: is_paid_amount_valid = paid_amount_input > 0;
$: is_everything_set =
editable.donor != null &&
((original_data.responseType == "DISTANCEDONATION" &&
editable?.runner != null) ||
original_data.responseType !== "DISTANCEDONATION");
$: changes_performed =
!(JSON.stringify(original_data) === JSON.stringify(editable)) ||
(original_data.responseType == "DISTANCEDONATION" &&
!(Math.floor(amount_input * 100) === original_data.amountPerDistance)) ||
(original_data.responseType !== "DISTANCEDONATION" &&
!(Math.floor(amount_input * 100) === original_data.amount)) ||
!(Math.floor(paid_amount_input * 100) === original_data.paidAmount);
$: save_enabled = changes_performed && is_amount_valid && is_everything_set;
const promise = DonationService.donationControllerGetOne(
params.donationid
).then((data) => {
data_loaded = true;
original_data = Object.assign({}, data);
editable = Object.assign({}, original_data);
paid_amount_input = data.paidAmount / 100;
if (data.responseType == "DISTANCEDONATION") {
amount_input = data.amountPerDistance / 100;
RunnerService.runnerControllerGetAll().then((val) => {
current_runners = val.map((r) => {
return { label: getDonorLabel(r), value: r };
});
runner = current_runners.find((g) => g.value.id == editable.runner.id);
});
} else {
amount_input = data.amount / 100;
}
DonorService.donorControllerGetAll().then((val) => {
current_donors = val.map((r) => {
return { label: getDonorLabel(r), value: r };
});
donor = current_donors.find((g) => g.value.id == editable.donor.id);
});
});
const getDonorLabel = (option) =>
option.firstname + " " + (option.middlename || "") + " " + option.lastname;
const filterDonors = (label, filterText, option) =>
label.toLowerCase().includes(filterText.toLowerCase()) ||
option.value.id.toString().startsWith(filterText.toLowerCase());
function submit() {
if (data_loaded === true && save_enabled) {
toast($_("updating-donation"));
let postdata = {};
editable.paidAmount = paid_amount_input * 100;
if (original_data.responseType === "DISTANCEDONATION") {
editable.amountPerDistance = Math.floor(amount_input * 100);
postdata = Object.assign(postdata, editable);
postdata.runner = postdata.runner.id;
postdata.donor = postdata.donor.id;
DonationService.donationControllerPutDistance(
original_data.id,
postdata
)
.then((resp) => {
Object.assign(original_data, editable);
original_data = original_data;
toast.success($_("donation-updated"));
})
.catch((err) => {});
} else {
editable.amount = Math.floor(amount_input * 100);
postdata = Object.assign(postdata, editable);
postdata.donor = postdata.donor.id;
DonationService.donationControllerPutFixed(original_data.id, postdata)
.then((resp) => {
Object.assign(original_data, editable);
original_data = original_data;
toast.success($_("donation-updated"));
})
.catch((err) => {});
}
} else {
}
}
function deleteDonation() {
DonationService.donationControllerRemove(original_data.id, false)
.then((resp) => {
toast.success($_("donation-deleted"));
location.replace("./");
})
.catch((err) => {
modal_open = true;
delete_donor = original_data;
});
}
</script>
{#await promise}
{$_("loading-donation-details")}
{:then}
<section class="container p-5 select-none">
<div class="flex flex-row mb-4">
<div class="mt-2 w-full">
<nav class="w-full flex">
<ol class="list-none flex flex-row items-center justify-start">
<li class="flex items-center">
<a class="mr-2" href="./"
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="inline-block"
><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg
>
{$_("donations")}</a
>
</li>
</ol>
</nav>
</div>
</div>
<div class="mb-4 text-3xl font-extrabold leading-tight">
{original_data.donor.firstname}
{original_data.donor.middlename || ""}
{original_data.donor.lastname}
&gt;
{#if original_data.responseType == "DISTANCEDONATION"}
{original_data.runner.firstname}
{original_data.runner.middlename || ""}
{original_data.runner.lastname}
{:else}
{$_("fixed-donation")}:
{amount_input.toFixed(2).toLocaleString("de-DE", { valute: "EUR" })}
{/if}
[#{original_data.id}]
<div data-id="donation_actions_${original_data.id}">
{#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:DELETE")}
{#if delete_triggered}
<button
on:click={deleteDonation}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm"
>{$_("confirm-deletion")}</button
>
<button
on:click={() => {
delete_triggered = !delete_triggered;
}}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm"
>{$_("cancel")}</button
>
{/if}
{#if !delete_triggered}
<button
on:click={() => {
delete_triggered = true;
}}
type="button"
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm"
>{$_("delete-donation")}</button
>
{/if}
{/if}
{#if !delete_triggered}
<button
disabled={!save_enabled}
class:opacity-50={!save_enabled}
type="button"
on:click={submit}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:w-auto sm:text-sm mb-1 lg:mb-0"
>{$_("save-changes")}</button
>
{/if}
</div>
</div>
<!-- -->
<div>
<span class="font-semibold text-gray-700"
>{$_("total-donation-amount")}:</span
>
<span
>{(editable.amount / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })}€</span
>
|
<span class="font-semibold text-gray-700">{$_("paid-amount")}:</span>
<span
>{(editable.paidAmount / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })}€</span
>
|
<span class="font-semibold text-gray-700">{$_("status")}:</span>
{#if editable.status == "PAID"}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-green-100 text-green-800"
>{$_("paid")}</span
>
{:else}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-red-100 text-red-800"
>{$_("open")}</span
>
{/if}
</div>
<br />
<div class=" mt-2 w-full">
<label for="donor" class="block font-semibold text-gray-700"
>{$_("donor")}</label
>
<Select
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
itemFilter={(label, filterText, option) =>
filterDonors(label, filterText, option)}
items={current_donors}
showChevron={true}
placeholder={$_("search-for-donor-name-or-id")}
noOptionsMessage={$_("no-donors-found")}
bind:selectedValue={donor}
on:select={(selectedValue) => {
editable.donor = selectedValue.detail.value;
editable.donor.donationAmount = original_data.donor.donationAmount;
editable.donor.paidDonationAmount =
original_data.donor.paidDonationAmount;
}}
on:clear={() => (editable.donor = null)}
/>
</div>
{#if original_data.responseType == "DISTANCEDONATION"}
<div class=" mt-2 w-full">
<label for="donor" class="block font-semibold text-gray-700"
>{$_("runner")}</label
>
<Select
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
itemFilter={(label, filterText, option) =>
filterDonors(label, filterText, option)}
items={current_runners}
showChevron={true}
placeholder={$_("search-for-runner-by-name-or-id")}
noOptionsMessage={$_("no-runners-found")}
bind:selectedValue={runner}
on:select={(selectedValue) =>
(editable.runner = selectedValue.detail.value)}
on:clear={() => (editable.runner = null)}
/>
</div>
{/if}
<div class=" mt-2 w-full">
<label for="lastname" class="font-semibold text-gray-700">
{#if original_data.responseType == "DISTANCEDONATION"}
{$_("amount-per-kilometer")}
{:else}{$_("donation-amount")}{/if}
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input
autocomplete="off"
class:border-red-500={!is_amount_valid}
class:focus:border-red-500={!is_amount_valid}
class:focus:ring-red-500={!is_amount_valid}
bind:value={amount_input}
type="number"
step="0.01"
name="donation_amount_eur"
class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 p-2"
placeholder="2.00"
/>
<span
class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500"
>€</span
>
</div>
{#if !is_amount_valid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("donation-amount-must-be-greater-that-0-00eur")}
</span>
{/if}
</div>
<div class="mt-2 w-full">
<label for="token" class="block font-semibold text-gray-700"
>{$_("paid-amount")}</label
>
<div
class="inline-flex border-gray-300 border rounded-l-md rounded-r-md bg-gray-50 text-gray-500 w-full"
>
<input
autocomplete="off"
class:border-red-500={!is_amount_valid}
class:focus:border-red-500={!is_amount_valid}
class:focus:ring-red-500={!is_amount_valid}
bind:value={paid_amount_input}
type="number"
step="0.01"
name="donation_amount_eur"
class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm p-2"
placeholder="2.00"
/>
<button
on:click={() => {
paid_amount_input = paid_amount_input = (
original_data.amount / 100
).toFixed(2);
}}
class="inline-flex items-center p-r-2 text-indigo-300 hover:text-indigo-700 text-sm"
>MAX</button
>
<span
class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm"
>€</span
>
</div>
{#if !is_paid_amount_valid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("payment-amount-must-be-greater-than-0-00eur")}
</span>
{/if}
</div>
</section>
{:catch error}
<PromiseError {error} />
{/await}
@@ -0,0 +1,18 @@
<script>
import { _ } from "svelte-i18n";
export let donor;
</script>
{#if !donor || donor.firstname == 0}
{$_("donor-has-no-associated-donations")}
{:else}
<div class="flex items-center">
<a
href="../donors/{donor.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800 border border-current"
>{donor.firstname}
{#if donor.middlename}{donor.middlename}{/if}
{donor.lastname}</a
>
</div>
{/if}
@@ -0,0 +1,18 @@
<script>
import { _ } from "svelte-i18n";
export let runner;
</script>
{#if !runner || runner.firstname == 0}
{$_("fixed-donation")}
{:else}
<div class="text-sm font-medium text-gray-900">
<a
href="../runners/{runner.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800 border border-current"
>{runner.firstname}
{#if runner.middlename}{runner.middlename}{/if}
{runner.lastname}</a
>
</div>
{/if}
@@ -0,0 +1,16 @@
<script>
import { _ } from "svelte-i18n";
export let status;
</script>
{#if status == "PAID"}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-green-100 text-green-800"
>{$_("paid")}</span
>
{:else}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-red-100 text-red-800"
>{$_("open")}</span
>
{/if}
@@ -0,0 +1,21 @@
<script>
import { _ } from "svelte-i18n";
import TableActions from "../shared/TableActions.svelte";
export let detailsLink;
export let detailsAction;
export let deleteEnabled;
export let deleteAction;
export let paymentAction;
</script>
<button
on:click={paymentAction}
class="text-[#025a21] hover:text-green-900 mr-4">{$_("enter-payment")}</button
>
<TableActions
bind:detailsAction
bind:detailsLink
bind:deleteAction
bind:deleteEnabled
/>
+36
View File
@@ -0,0 +1,36 @@
<script>
import { _ } from "svelte-i18n";
import store from "../../store";
import AddDonationModal from "./AddDonationModal.svelte";
import DonationsOverview from "./DonationsOverview.svelte";
$: current_donations = [];
export let modal_open = false;
let addDonations;
</script>
<section class="container p-5">
<h4 class="mb-1 text-3xl font-extrabold leading-tight">
{$_("donations")}
</h4>
{#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:CREATE")}
<button
on:click={() => {
modal_open = true;
}}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:w-auto sm:text-sm"
>
{$_("add-donation")}
</button>
{/if}
<DonationsOverview bind:current_donations bind:addDonations />
</section>
{#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:CREATE")}
<AddDonationModal
on:created={(event) => {
addDonations(event.detail.donations);
}}
bind:modal_open
/>
{/if}
@@ -0,0 +1,12 @@
<script>
import { _ } from "svelte-i18n";
import donations_empty from "./donations.svg";
</script>
<div class="text-center items-center justify-center">
<p class="mb-16 text-lg text-gray-500">
<img class="m-auto mt-2" style="height:15rem" src={donations_empty} alt="" />
<span class="font-bold">{$_("there-are-no-donations-yet")}</span><br />
<span>{$_("add-your-fist-donation")}</span>
</p>
</div>
@@ -0,0 +1,291 @@
<script>
import { _ } from "svelte-i18n";
import { DonationService } from "@odit/lfk-client-js";
import store from "../../store";
import DonationsEmptyState from "./DonationsEmptyState.svelte";
import AddDonationPaymentModal from "./AddDonationPaymentModal.svelte";
import { onMount } from "svelte";
import {
createSvelteTable,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
renderComponent,
} from "@tanstack/svelte-table";
import { writable } from "svelte/store";
import TableBottom from "../shared/TableBottom.svelte";
import InputElement from "../shared/InputElement.svelte";
import TableHeader from "../shared/TableHeader.svelte";
import DonationDonor from "./DonationDonor.svelte";
import DonationRunner from "./DonationRunner.svelte";
import DonationStatus from "./DonationStatus.svelte";
import DonationTableAction from "./DonationTableAction.svelte";
import DeleteDonationModal from "./DeleteDonationModal.svelte";
import {
donationDonorFilter,
donationRunnerFilter,
} from "../shared/tablefilters";
import toast from "svelte-french-toast";
$: searchvalue = "";
$: active_deletes = [];
$: active_edits = [];
$: selected =
$table?.getSelectedRowModel().rows.map((row) => row.index) || [];
$: dataLoaded = false;
export let current_donations = [];
export const addDonations = (donations) => {
current_donations = current_donations.concat(...donations);
options.update((options) => ({
...options,
data: current_donations,
}));
};
//Section table
const columns = [
{
accessorKey: "id",
header: () => "id",
filterFn: `equalsString`,
},
{
accessorKey: "donor",
header: () => $_("donor"),
cell: (info) => {
return renderComponent(DonationDonor, { donor: info.getValue() });
},
filterFn: `donor`,
},
{
accessorKey: "runner",
header: () => $_("runner"),
cell: (info) => {
return renderComponent(DonationRunner, { runner: info.getValue() });
},
filterFn: `runner`,
},
{
accessorKey: "amountPerDistance",
header: () => $_("amount-per-kilometer"),
cell: (info) => {
if (!info.getValue()) {
return $_("fixed-donation");
}
return `${(info.getValue() / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })} €`;
},
enableColumnFilter: false,
},
{
accessorKey: "amount",
header: () => $_("donation-amount"),
cell: (info) => {
return `${(info.getValue() / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })} €`;
},
enableColumnFilter: false,
},
{
accessorKey: "paidAmount",
header: () => $_("total-paid-amount"),
cell: (info) => {
return `${(info.getValue() / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })} €`;
},
enableColumnFilter: false,
},
{
accessorKey: "status",
header: () => $_("status"),
cell: (info) => {
return renderComponent(DonationStatus, { status: info.getValue() });
},
enableColumnFilter: false,
},
{
accessorKey: "actions",
header: () => $_("action"),
cell: (info) => {
return renderComponent(DonationTableAction, {
detailsLink: `./${info.row.original.id}`,
deleteAction: () => {
active_deletes = current_donations.filter(
(r) => r.id == info.row.original.id
);
},
paymentAction: () => {
active_edits = current_donations.filter(
(r) => r.id == info.row.original.id
);
},
deleteEnabled:
store.state.jwtinfo.userdetails.permissions.includes(
"DONATION:DELETE"
),
});
},
enableColumnFilter: false,
enableSorting: false,
},
];
const options = writable({
data: [],
columns: columns,
initialState: {
pagination: {
pageSize: 50,
},
},
filterFns: {
donor: donationDonorFilter,
runner: donationRunnerFilter,
},
enableRowSelection: true,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
});
const table = createSvelteTable(options);
async function deleteDonation(delete_donation_id) {
await DonationService.donationControllerRemove(delete_donation_id, true);
current_donations = current_donations.filter(
(r) => r.id !== delete_donation_id
);
options.update((options) => ({
...options,
data: current_donations,
}));
toast.success($_("donation-deleted"));
}
onMount(async () => {
let page = 0;
let pagesize = 300;
while (page >= 0) {
const donations = await DonationService.donationControllerGetAll(
page,
pagesize
);
if (donations.length == 0) {
page = -2;
}
current_donations = current_donations.concat(...donations);
options.update((options) => ({
...options,
data: current_donations,
}));
dataLoaded = true;
page++;
}
});
</script>
<AddDonationPaymentModal
original_data={active_edits[0]}
payment_modal_open={active_edits.length > 0}
paid_amount_input={(active_edits[0]?.paidAmount || 0) / 100}
on:created={(event) => {
current_donations = current_donations.map((d)=>{
if(d.id === event.detail.donation.id){
d.paidAmount = event.detail.donation.paidAmount;
}
return d;
})
options.update((options) => ({
...options,
data: current_donations,
}));
}}
/>
<DeleteDonationModal
delete_donation={active_deletes[0]}
modal_open={active_deletes.length > 0}
on:delete={(event) => {
deleteDonation(event.detail.id);
}}
/>
{#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:GET")}
{#if !dataLoaded}
<div
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
role="alert"
>
<p class="font-bold">{$_("donations-are-being-loaded")}</p>
<p class="text-sm">{$_("this-might-take-a-moment")}</p>
</div>
{:else if current_donations.length === 0}
<DonationsEmptyState />
{:else}
<input
type="search"
bind:value={searchvalue}
placeholder={$_("datatable.search")}
aria-label={$_("datatable.search")}
class="mb-2 w-full sm:w-auto mt-1 sm:mt-0 p-2 rounded-md border"
/>
<div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"
>
<table class="w-full">
<thead class="border-b border-gray-400">
{#each $table.getHeaderGroups() as headerGroup}
<tr class="select-none">
<th class="inset-y-0 left-0 px-4 py-2 text-left w-px">
<InputElement
type="checkbox"
checked={$table.getIsAllRowsSelected()}
indeterminate={$table.getIsSomeRowsSelected()}
on:change={() => $table.toggleAllRowsSelected()}
/>
</th>
{#each headerGroup.headers as header}
<TableHeader {header} />
{/each}
</tr>
{/each}
</thead>
<tbody>
{#each $table.getRowModel().rows as row}
<tr class="odd:bg-white even:bg-gray-100">
<td class="inset-y-0 left-0 px-4 py-2 text-center w-px">
<InputElement
type="checkbox"
checked={row.getIsSelected()}
on:change={() => row.toggleSelected()}
/>
</td>
{#each row.getVisibleCells() as cell}
<td>
<svelte:component
this={flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
/>
</td>
{/each}
</tr>
{/each}
</tbody>
</table>
</div>
<div class="h-2" />
<TableBottom {table} {selected} />
{/if}
{/if}
<style>
table tbody tr td:nth-child(2) {
font-family: monospace;
}
</style>
+1
View File
@@ -0,0 +1 @@
<svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="598.11" height="535.11"><path d="M3.35 120.07a4.6 4.6 0 00-3.18 5.66l76.72 273.98a4.6 4.6 0 005.65 3.18l282.82-79.19a4.6 4.6 0 003.18-5.66L291.82 44.07a4.6 4.6 0 00-5.65-3.19z" fill="#e6e6e6"/><path d="M86.1 389.95l269.5-75.46-72.99-260.67-269.5 75.46z" fill="#fff"/><path d="M48.74 164.1c-1.8.5-2.54 3.48-1.65 6.65s3.07 5.33 4.87 4.83l122.91-34.42c1.8-.5 2.54-3.49 1.66-6.65s-3.08-5.34-4.87-4.84zM58.64 199.44c-1.8.5-2.54 3.5-1.65 6.66s3.07 5.34 4.87 4.83l122.91-34.42c1.8-.5 2.54-3.49 1.65-6.65s-3.07-5.34-4.86-4.83zM68.42 234.39c-1.8.5-2.54 3.49-1.65 6.66s3.07 5.33 4.87 4.83l122.92-34.42c1.8-.5 2.54-3.5 1.65-6.66s-3.07-5.33-4.87-4.83zM78.32 269.74c-1.8.5-2.54 3.49-1.65 6.66s3.07 5.33 4.87 4.83l122.92-34.42c1.8-.5 2.54-3.49 1.65-6.66s-3.07-5.33-4.87-4.83zM234.04 112.61a5.97 5.97 0 103.21 11.5l22.98-6.44a5.97 5.97 0 00-3.22-11.49zM243.74 147.28a5.97 5.97 0 103.22 11.49l22.98-6.43a5.97 5.97 0 00-3.22-11.5zM253.45 181.95a5.97 5.97 0 103.22 11.49l22.98-6.44a5.97 5.97 0 00-3.22-11.49zM263.16 216.61a5.97 5.97 0 003.21 11.5l22.98-6.44a5.97 5.97 0 00-3.21-11.49z" fill="#e6e6e6"/><path d="M272.43 276.7a7.6 7.6 0 104.1 14.64l29.28-8.2a7.6 7.6 0 00-4.1-14.64z" fill="#6c63ff"/><path fill="#e6e6e6" d="M85.9 307.81l216.66-60.67.54 1.93-216.67 60.67z"/><path fill="#a0616a" d="M520.2 506.07l-17.38 4.2-24.47-65.02 25.65-6.2 16.2 67.02z"/><path d="M472.85 535.11l-.12-.48a22.23 22.23 0 0116.37-26.8l34-8.23 5.33 22.08z" fill="#2f2e41"/><path fill="#a0616a" d="M443.28 517.91H425.4l-8.5-68.96h26.38v68.96z"/><path d="M447.6 535.01h-57.18v-.5a22.2 22.2 0 0122.2-22.2h34.99zM416.88 490.99l-17.36-206.87 71.86-13.25.28-.05 21.03 13.52-7.32 76.14 33.7 118.7-29.1 7.65-33.75-110.08-7.73-33.48-3.96 43.5 2.94 107.28z" fill="#2f2e41"/><path d="M397.3 288.81l-.2-.24 24.84-186.96.03-.24.17-.18c.37-.36 9.07-8.96 18.02-8.96 1.3 0 2.52-.03 3.7-.06 6.85-.18 12.26-.32 18.69 6.1 6.55 6.56 27.92 30.47 27.92 63.23 0 31.7 2.88 130.22 2.91 131.21l.04 1.4-1.16-.76c-.3-.19-29.03-18.49-53.14-1.48-7.53 5.32-14.3 7.18-20.09 7.18-13.47 0-21.62-10.1-21.73-10.24z" fill="#6c63ff"/><circle cx="737.3" cy="227.82" r="35.82" transform="rotate(-28.66 229.78 725.57)" fill="#a0616a"/><path d="M381.53 328.99a14.66 14.66 0 00.85-22.47l20.34-47.97-26.63 4.9-15.23 44.8A14.74 14.74 0 00381.53 329z" fill="#a0616a"/><path d="M361.88 291.67l6.55-13.83a2.7 2.7 0 01-.97-1c-6.12-10.6 30.84-98.67 33.3-104.51-.37-3.18-4.25-36.85-1.41-48.2 3.34-13.35 10.2-19.58 22.93-20.81 14.04-1.32 17.83 17.75 17.86 17.94l.02 49.02-16.12 56.43-36.75 74.97z" fill="#6c63ff"/><path d="M440.94 58.87c-4.3.56-7.54-3.83-9.04-7.9s-2.64-8.78-6.38-10.98c-5.1-3-11.62.61-17.45-.38-6.59-1.11-10.87-8.1-11.2-14.76s2.31-13.1 4.92-19.24l.9 7.64A15.16 15.16 0 01409.33 0l-1.17 11.22c.73-6.29 7.5-11.16 13.7-9.85l-.19 6.68c7.6-.9 15.28-1.81 22.91-1.12s15.31 3.1 21.1 8.13c8.64 7.51 11.8 19.89 10.74 31.3s-5.77 22.13-10.68 32.48c-1.23 2.6-2.94 5.54-5.8 5.88-2.58.3-4.93-1.86-5.73-4.32s-.41-5.14.07-7.69c.72-3.84 1.63-7.77.95-11.63s-3.45-7.66-7.33-8.13-7.86 3.97-6 7.4z" fill="#2f2e41"/><path fill="#3f3d56" d="M597.73 535.1H339.99v-2.11h258.12l-.38 2.1z"/></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

+444
View File
@@ -0,0 +1,444 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { DonorService } from "@odit/lfk-client-js";
import isEmail from "validator/es/lib/isEmail";
import isMobilePhone from "validator/es/lib/isMobilePhone";
import { createEventDispatcher } from "svelte";
import toast from "svelte-french-toast";
export let modal_open;
let firstname_input;
let lastname_input;
let middlename_input;
let phone_input;
let email_input;
let address_input1;
let address_input2;
let address_zipcode;
let address_city;
const dispatch = createEventDispatcher();
function focus(el) {
el.focus();
}
$: middlename_input_value = "";
$: phone_input_value = "";
$: email_input_value = "";
$: lastname_input_value = "";
$: firstname_input_value = "";
$: address_input1_value = "";
$: address_input2_value = "";
$: address_zipcode_value = "";
$: address_city_value = "";
$: processed_last_submit = true;
$: address_checked = false;
$: isPhoneValidOrEmpty =
(phone_input_value.includes("+") &&
isMobilePhone(
phone_input_value
.replaceAll("(", "")
.replaceAll(")", "")
.replaceAll("-", "")
.replaceAll(" ", "")
)) ||
phone_input_value === "";
$: isEmailValidOrEmpty =
isEmail(email_input_value) || email_input_value === "";
$: isLastnameValid = lastname_input_value.trim().length !== 0;
$: isFirstnameValid = firstname_input_value.trim().length !== 0;
$: isAddress1Valid = address_input1_value.trim().length !== 0;
$: iszipcodevalid = address_zipcode_value.trim().length !== 0;
$: iscityvalid = address_city_value.trim().length !== 0;
$: createbtnenabled =
isFirstnameValid &&
isLastnameValid &&
isEmailValidOrEmpty &&
isPhoneValidOrEmpty &&
((isAddress1Valid && iszipcodevalid && iscityvalid) ||
address_checked === false);
(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
})();
function submit() {
if (processed_last_submit === true) {
processed_last_submit = false;
toast.loading($_("donor-is-being-added"));
let address = {};
if (address_checked === true) {
address = {
address1: address_input1_value,
address2: address_input2_value || "",
postalcode: address_zipcode_value,
city: address_city_value,
country: "DE",
};
}
let postdata = {
firstname: firstname_input_value,
lastname: lastname_input_value,
address,
receiptNeeded: address_checked,
};
if (middlename_input_value) {
postdata.middlename = middlename_input_value;
}
if (phone_input_value) {
postdata.phone = phone_input_value;
}
if (email_input_value) {
postdata.email = email_input_value;
}
DonorService.donorControllerPost(postdata)
.then((result) => {
firstname_input_value = "";
lastname_input_value = "";
middlename_input_value = "";
email_input_value = "";
modal_open = false;
//
toast.dismiss();
toast.success($_("donor-added"));
dispatch("created", { donors: [result] });
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
});
}
}
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-4 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M9.33 11.5h2.17A4.5 4.5 0 0 1 16 16H8.999L9 17h8v-1a5.578 5.578 0 0 0-.886-3H19a5 5 0 0 1 4.516 2.851C21.151 18.972 17.322 21 13 21c-2.761 0-5.1-.59-7-1.625L6 10.071A6.967 6.967 0 0 1 9.33 11.5zM5 19a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v9zM18 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm-7-3a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_("create-a-new-donor")}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_(
"please-provide-the-nessecary-information-to-add-a-new-donor"
)}
</p>
</div>
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6">
<label
for="firstname"
class="block text-sm font-medium text-gray-700"
>{$_("first-name")}</label
>
<input
use:focus
autocomplete="off"
placeholder={$_("first-name")}
class:border-red-500={!isFirstnameValid}
class:focus:border-red-500={!isFirstnameValid}
class:focus:ring-red-500={!isFirstnameValid}
bind:value={firstname_input_value}
bind:this={firstname_input}
type="text"
name="firstname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isFirstnameValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("first-name-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="trackname"
class="block text-sm font-medium text-gray-700"
>{$_("middle-name")}</label
>
<input
autocomplete="off"
placeholder={$_("middle-name")}
bind:value={middlename_input_value}
bind:this={middlename_input}
type="text"
name="trackname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
</div>
<div class="col-span-6">
<label
for="lastname"
class="block text-sm font-medium text-gray-700"
>{$_("last-name")}</label
>
<input
autocomplete="off"
placeholder={$_("last-name")}
class:border-red-500={!isLastnameValid}
class:focus:border-red-500={!isLastnameValid}
class:focus:ring-red-500={!isLastnameValid}
bind:value={lastname_input_value}
bind:this={lastname_input}
type="text"
name="lastname"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isLastnameValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("last-name-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="phone"
class="block text-sm font-medium text-gray-700"
>{$_("phone")}</label
>
<input
autocomplete="off"
placeholder={$_("phone")}
class:border-red-500={!isPhoneValidOrEmpty}
class:focus:border-red-500={!isPhoneValidOrEmpty}
class:focus:ring-red-500={!isPhoneValidOrEmpty}
bind:value={phone_input_value}
bind:this={phone_input}
type="tel"
name="phone"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isPhoneValidOrEmpty}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{@html $_(
"the-provided-phone-number-is-invalid-less-than-br-greater-than-please-enter-a-valid-international-number"
)}
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="email"
class="block text-sm font-medium text-gray-700"
>{$_("e-mail-adress")}</label
>
<input
autocomplete="off"
placeholder={$_("e-mail-adress")}
class:border-red-500={!isEmailValidOrEmpty}
class:focus:border-red-500={!isEmailValidOrEmpty}
class:focus:ring-red-500={!isEmailValidOrEmpty}
bind:value={email_input_value}
bind:this={email_input}
type="email"
name="email"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isEmailValidOrEmpty}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-email-is-required")}
</span>
{/if}
</div>
<div class="flex items-start">
<div class="flex items-center h-5">
<input
bind:checked={address_checked}
id="comments"
name="comments"
type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
/>
</div>
<div class="ml-3 text-sm">
<label for="comments" class="font-semibold text-gray-700"
>{$_("receipt-needed")}</label
>
</div>
</div>
{#if address_checked === true}
<div class="col-span-6">
<label
for="address1"
class="block text-sm font-medium text-gray-700"
>{$_("address")}</label
>
<input
autocomplete="off"
placeholder="Address"
class:border-red-500={!isAddress1Valid}
class:focus:border-red-500={!isAddress1Valid}
class:focus:ring-red-500={!isAddress1Valid}
bind:value={address_input1_value}
bind:this={address_input1}
type="text"
name="address1"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isAddress1Valid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("address-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="address2"
class="block text-sm font-medium text-gray-700"
>{$_("apartment-suite-etc")}</label
>
<input
autocomplete="off"
placeholder={$_("apartment-suite-etc")}
bind:value={address_input2_value}
bind:this={address_input2}
type="text"
name="address2"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
</div>
<div class="col-span-6">
<label
for="zipcode"
class="block text-sm font-medium text-gray-700"
>{$_("zip-postal-code")}</label
>
<input
autocomplete="off"
placeholder={$_("zip-postal-code")}
class:border-red-500={!iszipcodevalid}
class:focus:border-red-500={!iszipcodevalid}
class:focus:ring-red-500={!iszipcodevalid}
bind:value={address_zipcode_value}
bind:this={address_zipcode}
type="text"
name="zipcode"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !iszipcodevalid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-zipcode-postal-code-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label
for="city"
class="block text-sm font-medium text-gray-700"
>City</label
>
<input
autocomplete="off"
placeholder="City"
class:border-red-500={!iscityvalid}
class:focus:border-red-500={!iscityvalid}
class:focus:ring-red-500={!iscityvalid}
bind:value={address_city_value}
bind:this={address_city}
type="text"
name="city"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !iscityvalid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-city-is-required")}
</span>
{/if}
</div>
{/if}
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 grid gap-2 rounded-b">
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("create")}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}
@@ -0,0 +1,90 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { createEventDispatcher } from "svelte";
export let modal_open;
export let delete_donor;
const dispatch = createEventDispatcher();
function cancelDelete() {
modal_open = false;
dispatch("cancelDelete", { id: delete_donor.id });
}
function deleteDonor() {
dispatch("delete", { id: delete_donor.id });
}
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={cancelDelete}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-4 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop"
/>
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
><path fill="none" d="M0 0h24v24H0z" /><path
d="M9.33 11.5h2.17A4.5 4.5 0 0116 16H9v1h8v-1a5.58 5.58 0 00-.89-3H19a5 5 0 014.52 2.85A13.15 13.15 0 0113 21c-2.76 0-5.1-.59-7-1.63v-9.3a6.97 6.97 0 013.33 1.43zM5 19a1 1 0 01-1 1H2a1 1 0 01-1-1v-9a1 1 0 011-1h2a1 1 0 011 1v9zM18 5a3 3 0 110 6 3 3 0 010-6zm-7-3a3 3 0 110 6 3 3 0 010-6z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_(
"do-you-want-to-delete-this-donor-with-all-related-donations"
)}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_("all-associated-donations-will-get-deleted-as-well")}
</p>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 grid gap-2 rounded-b">
<button
on:click={deleteDonor}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("confirm-delete-donor-with-all-donations")}
</button>
<button
on:click={cancelDelete}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel-keep-donor")}
</button>
</div>
</div>
</div>
</div>
{/if}
+14
View File
@@ -0,0 +1,14 @@
<script>
import { _ } from "svelte-i18n";
export let address;
</script>
{#if !address || !address.address1}
{$_("no-address")}
{:else}
{address.address1}<br />
<!-- {address.address2 || ''}<br /> -->
{address.postalcode}
{address.city}
{address.country}
{/if}
+413
View File
@@ -0,0 +1,413 @@
<script>
import { DonorService } from "@odit/lfk-client-js";
import { _ } from "svelte-i18n";
import store from "../../store";
import toast from "svelte-french-toast";
import isEmail from "validator/es/lib/isEmail";
import PromiseError from "../base/PromiseError.svelte";
let data_loaded = false;
export let params;
$: delete_triggered = false;
$: original_data = {};
$: editable = {};
$: changes_performed = !(
JSON.stringify(original_data) === JSON.stringify(editable)
);
$: isEmailValid =
(editable.email || "") === "" ||
(editable.email && isEmail(editable.email || ""));
$: isFirstnameValid = editable.firstname !== "";
$: isLastnameValid = editable.lastname !== "";
$: save_enabled =
changes_performed &&
isFirstnameValid &&
isLastnameValid &&
isEmailValid &&
isPhoneValidOrEmpty &&
((isAddress1Valid && iszipcodevalid && iscityvalid) ||
editable.address_checked === false);
const promise = DonorService.donorControllerGetOne(params.donorid).then(
(data) => {
data_loaded = true;
original_data = Object.assign(original_data, data);
editable = Object.assign(editable, original_data);
editable.address_checked = editable.address.address1 !== null;
original_data.address_checked = editable.address.address1 !== null;
if (editable.address_checked === false) {
editable.address = {
address1: "",
address2: "",
city: "",
postalcode: "",
country: "",
};
}
}
);
$: isPhoneValidOrEmpty =
editable.phone?.includes("+") ||
editable.phone === "" ||
editable.phone === null;
$: isAddress1Valid = editable.address?.address1?.trim().length !== 0;
$: iszipcodevalid = editable.address?.postalcode?.trim().length !== 0;
$: iscityvalid = editable.address?.city?.trim().length !== 0;
function submit() {
if (data_loaded === true && save_enabled) {
toast($_("donor-is-being-updated"));
editable.address.country = "DE";
if (editable.address_checked === false) {
editable.address = null;
}
if (editable.email) editable.email = editable.email;
else editable.email = null;
if (editable.phone) editable.phone = editable.phone;
else editable.phone = null;
if (editable.middlename) editable.middlename = editable.middlename;
editable.receiptNeeded = editable.address_checked;
DonorService.donorControllerPut(original_data.id, editable)
.then((resp) => {
Object.assign(original_data, editable);
original_data = original_data;
toast.success($_("updated-donor"));
})
.catch((err) => {});
} else {
}
}
function deleteDonor() {
DonorService.donorControllerRemove(original_data.id, true)
.then((resp) => {
toast.success($_("donor-deleted"));
location.replace("./");
})
.catch((err) => {
console.log(err);
});
}
</script>
{#await promise}
{$_("loading-donor-details")}
{:then}
<section class="container p-5 select-none">
<div class="flex flex-row mb-4">
<div class="w-full">
<nav class="w-full flex">
<ol class="list-none flex flex-row items-center justify-start">
<li class="flex items-center">
<a class="mr-2" href="./"
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="inline-block"
><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg
>
{$_("donors")}</a
>
</li>
</ol>
</nav>
</div>
</div>
<div class="mb-4 text-3xl font-extrabold leading-tight">
{original_data.firstname}
{original_data.middlename || ""}
{original_data.lastname}
<div data-id="donor_actions_${editable.id}">
{#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:DELETE")}
{#if delete_triggered}
<button
on:click={deleteDonor}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm"
>{$_("confirm-deletion")}</button
>
<button
on:click={() => {
delete_triggered = !delete_triggered;
}}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm"
>{$_("cancel")}</button
>
{/if}
{#if !delete_triggered}
<button
on:click={() => {
delete_triggered = true;
}}
type="button"
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm"
>{$_("delete-donor")}</button
>
{/if}
{/if}
{#if !delete_triggered}
<button
disabled={!save_enabled}
class:opacity-50={!save_enabled}
type="button"
on:click={submit}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:w-auto sm:text-sm mb-1 lg:mb-0"
>{$_("save-changes")}</button
>
{/if}
</div>
</div>
<!-- -->
<div>
<span class="font-semibold text-gray-700"
>{$_("total-donation-amount")}:</span
>
<span
>{(editable.donationAmount / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })}€</span
>
|
<span class="font-semibold text-gray-700">{$_("total-paid-amount")}:</span
>
<span
>{(editable.paidDonationAmount / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })}€</span
>
<br />
<span class="font-semibold text-gray-700">{$_("donations")}:</span>
{#if original_data.donations.length > 0}
{#each original_data.donations as d}
{#if d.responseType === "DISTANCEDONATION"}
<a
href="../donations/{d.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-600 text-white mr-1"
>{d.runner.firstname}
{d.runner.middlename || ""}
{d.runner.lastname}</a
>
{:else}
<a
href="../donations/{d.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-green-700 text-white mr-1"
>{$_("fixed-donation")}:
{(d.amount / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })}€</a
>
{/if}
{/each}
{:else}{$_("donor-has-no-associated-donations")}{/if}
</div>
<div class="mt-2 w-full">
<label for="firstname" class="font-semibold text-gray-700"
>{$_("first-name")}</label
>
<input
autocomplete="off"
placeholder={$_("first-name")}
type="text"
class:border-red-500={!isFirstnameValid}
class:focus:border-red-500={!isFirstnameValid}
class:focus:ring-red-500={!isFirstnameValid}
bind:value={editable.firstname}
name="firstname"
class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isFirstnameValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("first-name-is-required")}
</span>
{/if}
</div>
<div class="mt-2 w-full">
<label for="middlename" class="font-semibold text-gray-700"
>{$_("middle-name")}</label
>
<input
autocomplete="off"
placeholder={$_("middle-name")}
type="text"
bind:value={editable.middlename}
name="middlename"
class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
</div>
<div class="mt-2 w-full">
<label for="lastname" class="font-semibold text-gray-700"
>{$_("last-name")}</label
>
<input
autocomplete="off"
placeholder={$_("last-name")}
type="text"
bind:value={editable.lastname}
class:border-red-500={!isLastnameValid}
class:focus:border-red-500={!isLastnameValid}
class:focus:ring-red-500={!isLastnameValid}
name="lastname"
class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isLastnameValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("last-name-is-required")}
</span>
{/if}
</div>
<div class="mt-2 w-full">
<label for="email" class="font-semibold text-gray-700"
>{$_("e-mail-adress")}</label
>
<input
autocomplete="off"
placeholder={$_("e-mail-adress")}
type="email"
bind:value={editable.email}
class:border-red-500={!isEmailValid}
class:focus:border-red-500={!isEmailValid}
class:focus:ring-red-500={!isEmailValid}
name="email"
class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isEmailValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-email-is-required")}
</span>
{/if}
</div>
<div class="mt-2 w-full">
<label for="phone" class="font-semibold text-gray-700"
>{$_("phone")}</label
>
<input
autocomplete="off"
placeholder={$_("phone")}
type="tel"
class:border-red-500={!isPhoneValidOrEmpty}
class:focus:border-red-500={!isPhoneValidOrEmpty}
class:focus:ring-red-500={!isPhoneValidOrEmpty}
bind:value={editable.phone}
name="phone"
class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isPhoneValidOrEmpty}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-international-phone-number-is-required")}
</span>
{/if}
</div>
<div class="flex items-start mt-2">
<div class="flex items-center h-5">
<input
bind:checked={editable.address_checked}
id="comments"
name="comments"
type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
/>
</div>
<div class="ml-3">
<label for="comments" class="font-semibold text-gray-700"
>{$_("receipt-needed")}</label
>
</div>
</div>
{#if editable.address_checked === true}
<div class="col-span-6">
<label for="address1" class="block font-medium text-gray-700"
>{$_("address")}</label
>
<input
autocomplete="off"
placeholder="Address"
class:border-red-500={!isAddress1Valid}
class:focus:border-red-500={!isAddress1Valid}
class:focus:ring-red-500={!isAddress1Valid}
bind:value={editable.address.address1}
type="text"
name="address1"
class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !isAddress1Valid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("address-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label for="address2" class="block font-medium text-gray-700"
>{$_("apartment-suite-etc")}</label
>
<input
autocomplete="off"
placeholder={$_("apartment-suite-etc")}
bind:value={editable.address.address2}
type="text"
name="address2"
class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
</div>
<div class="col-span-6">
<label for="zipcode" class="block font-medium text-gray-700"
>{$_("zip-postal-code")}</label
>
<input
autocomplete="off"
placeholder={$_("zip-postal-code")}
class:border-red-500={!iszipcodevalid}
class:focus:border-red-500={!iszipcodevalid}
class:focus:ring-red-500={!iszipcodevalid}
bind:value={editable.address.postalcode}
type="text"
name="zipcode"
class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !iszipcodevalid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-zipcode-postal-code-is-required")}
</span>
{/if}
</div>
<div class="col-span-6">
<label for="city" class="block font-medium text-gray-700"
>{$_("city")}</label
>
<input
autocomplete="off"
placeholder={$_("city")}
class:border-red-500={!iscityvalid}
class:focus:border-red-500={!iscityvalid}
class:focus:ring-red-500={!iscityvalid}
bind:value={editable.address.city}
type="text"
name="city"
class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
/>
{#if !iscityvalid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("valid-city-is-required")}
</span>
{/if}
</div>
{/if}
</section>
{:catch error}
<PromiseError {error} />
{/await}
@@ -0,0 +1,29 @@
<script>
import { _ } from "svelte-i18n";
export let donations;
</script>
{#if !donations || donations.length == 0}
{$_("donor-has-no-associated-donations")}
{:else}
{#each donations as donation}
{#if donation.responseType === "DISTANCEDONATION"}
<a
href="../donations/{donation.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-600 text-white mr-1"
>{donation.runner.firstname}
{donation.runner.middlename || ""}
{donation.runner.lastname}</a
>
{:else}
<a
href="../donations/{donation.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-green-700 text-white mr-1"
>{$_("fixed-donation")}:
{(donation.amount / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })}€</a
>
{/if}
{/each}
{/if}
+77
View File
@@ -0,0 +1,77 @@
<script>
import { _ } from "svelte-i18n";
import store from "../../store";
import AddDonorModal from "./AddDonorModal.svelte";
import DonorsOverview from "./DonorsOverview.svelte";
$: current_donors = [];
export let modal_open = false;
let addDonors;
</script>
<section class="container p-5">
<h4 class="mb-1 text-3xl font-extrabold leading-tight">
{$_("donors")}
</h4>
{#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:CREATE")}
<button
on:click={() => {
modal_open = true;
}}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:w-auto sm:text-sm mb-1 lg:mb-0"
>
{$_("add-donor")}
</button>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:GET")}
<button
on:click={() => {
const data = current_donors
.filter((d) => d.receiptNeeded === true)
.map(function (d) {
d.address.address2 =
d.address.address2 === "" ? "" : " " + d.address.address2;
const address = `${d.address.address1}${d.address.address2}, ${d.address.postalcode} ${d.address.city}, ${d.address.country}`;
return [
d.firstname,
d.middlename,
d.lastname,
(d.paidDonationAmount/100).toFixed(2),
address,
];
});
let csv = `${$_("csv_import__firstname")};${$_(
"csv_import__middlename"
)};${$_("csv_import__lastname")};${$_(
"total_donation_amount_in_eur"
)};${$_("address")}\n`;
data.forEach(function (row) {
csv += row.join(";");
csv += "\n";
});
let hiddenElement = document.createElement("a");
hiddenElement.href = "data:text/csv;charset=utf-8," + encodeURI(csv);
hiddenElement.target = "_blank";
hiddenElement.download = `${$_(
"filename_sponsoringquittungsliste"
)}.csv`;
hiddenElement.click();
hiddenElement.remove();
}}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:w-auto sm:text-sm mb-1 lg:mb-0"
>
{$_("sponsoring-quittungs-liste_herunterladen")}
</button>
{/if}
<DonorsOverview bind:current_donors bind:addDonors />
</section>
{#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:CREATE")}
<AddDonorModal
on:created={(event) => {
addDonors(event.detail.donors);
}}
bind:modal_open
/>
{/if}

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