Compare commits

320 Commits
Author SHA1 Message Date
Björn Fromme 97f8baba06 fix: adopt general styles to error page template 2026-01-06 08:34:24 +01:00
Björn Fromme 3ffa80e2bc chore: update deployer config 2026-01-06 08:30:56 +01:00
Björn Fromme ab1a21dffc chore: update project dependencies 2026-01-06 08:26:22 +01:00
Björn Fromme bccd8c6fc3 chore: merge master into feature branch 2026-01-05 18:25:14 +01:00
Björn Fromme 2ea298854d fix: restore .user.ini from master 2026-01-05 18:17:38 +01:00
Björn Fromme b7e4f29813 chore: update upgrade plan with current state of the project 2026-01-05 17:34:02 +01:00
Björn Fromme 7780646601 chore: replace claude code with opencode inside ddev container 2026-01-05 17:24:41 +01:00
Björn Fromme 0f58f07757 chore: update project dependencies 2026-01-05 17:20:44 +01:00
Björn Fromme ef263e064a feat: add env variable for website base url 2026-01-05 17:20:18 +01:00
Björn Fromme 7127b4d050 chore: install claude code in ddev container for security reasons 2025-12-31 14:02:53 +01:00
Björn Fromme 42744fa30f chore: complete scheduler config for email notifications 2025-12-22 11:07:56 +01:00
Björn Fromme be3f6e6288 feat: remove outdated log entries scheduled 2025-12-22 11:07:33 +01:00
Björn Fromme 9291adfdff fix: fail gracefully when remote XML data cannot be read during sync 2025-12-22 08:29:57 +01:00
Björn Fromme c9426eff3b fix: catch travel data not found errors to show proper flash message 2025-12-19 17:54:25 +01:00
Björn Fromme cd350c212e chore: update project dependencies 2025-12-19 17:29:33 +01:00
Björn Fromme 1f1ac1a0cc docs: add inline documentation where missing 2025-12-19 17:26:59 +01:00
Björn Fromme 2dd5b7ad64 chore: cleanup 2025-12-19 17:26:39 +01:00
Björn Fromme 62ac8038dc feat: cron controlled cli command to sync xml data with remote 2025-12-19 17:06:27 +01:00
Björn Fromme 5f94f0487b chore: cleanup flysystem config 2025-12-19 16:07:12 +01:00
Björn Fromme 64880355e8 chore: update json test-data for pickups planning 2025-12-17 17:16:41 +01:00
Björn Fromme 1dc8489239 fix: avoid duplicated pickup planning entries 2025-12-17 17:05:38 +01:00
Björn Fromme 5831294d33 chore: reduce noise in logs 2025-12-17 16:44:11 +01:00
Björn Fromme 073bbdc0f8 feat: add logging to api endpoint 2025-12-17 16:34:57 +01:00
Björn Fromme ef75383885 fix: don't show bulk insurance labels in summary 2025-12-17 16:04:19 +01:00
Björn Fromme bfb25a4051 feat: accept multiple travel codes per pickup planning 2025-12-17 14:23:05 +01:00
Björn Fromme f55febd545 chore: update project dependencies 2025-12-17 10:23:06 +01:00
Björn Fromme d27b78cec1 chore: rotate auth log 2025-12-17 10:22:37 +01:00
Björn Fromme 1bb145e3be feat: forcibly invalidate availabilities cache on booking start 2025-12-16 13:46:54 +01:00
Björn Fromme 59b9a42009 feat: loading indicator on initial page load 2025-12-16 13:44:25 +01:00
Björn Fromme a576fa2d23 fix: adopt changes in test 2025-12-16 13:31:06 +01:00
Björn Fromme 14fe9bd44f feat: load availability data once per booking session 2025-12-16 13:30:45 +01:00
Björn Fromme cce59b8ed6 chore: disable saving cookies for api requests 2025-12-16 12:23:40 +01:00
Björn Fromme 8904e1c7fe feat: log pickups planning data api calls 2025-12-16 12:17:41 +01:00
Björn Fromme a0f763af63 chore: update project dependencies 2025-12-16 09:59:15 +01:00
Björn Fromme 667c9d4677 chore: reduce logger noise 2025-12-14 17:17:19 +01:00
Björn Fromme 1622f2be6a chore: retain xml dumps for three days to save on webspace 2025-12-14 17:10:09 +01:00
Björn Fromme 28914d6586 feat: rotate auth logfile 2025-12-12 20:15:56 +01:00
Björn Fromme cfc3957fec chore: update project dependencies 2025-12-12 20:06:45 +01:00
Björn Fromme aee2eb848d fix: adopt changed response class 2025-12-12 20:06:19 +01:00
Björn Fromme 42f17db542 feat: extended oauth2 user info and refactored authenticator 2025-12-12 19:57:34 +01:00
Björn Fromme 6315fbd0f7 fix: ensure template variable exists 2025-12-12 19:46:48 +01:00
Björn Fromme 79e5a3c12d feat: adjust oauth2 implementation for TYPO3 backend login 2025-12-12 16:31:32 +01:00
Björn Fromme e9c1dd8b9d feat: basic themes for event sites 2025-12-12 13:13:36 +01:00
Björn Fromme b1ff6989ec feat: api endpoints for pickups planning 2025-12-12 09:44:38 +01:00
Björn Fromme 1d97a19982 feat: always show all available ski passes but readonly if age doesn't match 2025-12-12 08:47:25 +01:00
Björn Fromme c3519124b7 feat: update labels of voucher fields
addresses #869bf8tzv
2025-12-12 08:09:34 +01:00
Björn Fromme 05c769bab2 feat: use query parameters for booking urls 2025-12-11 16:14:31 +01:00
Björn Fromme c1539a47f9 fix: properly assign readonly state to form fields for unavailable services 2025-12-11 12:07:19 +01:00
Björn Fromme f54f66cd32 fix: reset room assignments after updated selection if required 2025-12-11 11:27:48 +01:00
Björn Fromme c8a33cdf43 fix: assign correct return types 2025-12-11 11:26:46 +01:00
Björn Fromme b4c03160ca feat: consistent display of included services and prices 2025-12-11 11:17:03 +01:00
Björn Fromme 72cd36a573 feat: enable logging for contact form api endpoint 2025-12-11 09:33:41 +01:00
Björn Fromme 4d3a4b7c04 chore: update project dependencies 2025-12-10 18:01:34 +01:00
Björn Fromme b9dfeb2d3e feat: backport contact form api endpoint 2025-12-10 18:00:51 +01:00
Björn Fromme e42ef2d3c9 feat: show unavailable transportation services as readonly 2025-12-10 17:15:05 +01:00
Björn Fromme bb69a28ec2 fix: don't show incorrect notification about updated rentals 2025-12-10 15:40:17 +01:00
Björn Fromme e8c2261b7e feat: show inquiry status with rooms in step 1 2025-12-10 15:33:13 +01:00
Björn Fromme 7665385cbf feat: hide parking from participants under 18 2025-12-10 14:37:06 +01:00
Björn Fromme 346dee23e4 fix: don't auto assign discounted transport to babies 2025-12-10 14:09:52 +01:00
Björn Fromme 109f36e7f5 chore: simplify parameter handling 2025-12-10 13:57:48 +01:00
Björn Fromme 0e9c5e6e1a feat: configurable choices for body dimensions
closes #8697phk21
2025-12-10 13:48:47 +01:00
Björn Fromme 145a08e511 chore: update deployer config for prod 2025-12-10 13:10:17 +01:00
Björn Fromme 2b8046b416 feat: re-implement contact form submissions api endpoint for website 2025-12-10 09:29:19 +01:00
Björn Fromme e27b5da3c8 feat: adjust participant number size depending on value 2025-12-09 20:52:12 +01:00
Björn Fromme 613e0b9a5c feat: update deployer config to build assets upfront 2025-12-09 20:48:36 +01:00
Björn Fromme 0564e3c424 feat: align rendering of pickups field with other services 2025-12-09 20:43:58 +01:00
Björn Fromme 32c73ab7b1 fix: avoid loading indicator issues when using browser history for navigation 2025-12-09 15:13:04 +01:00
Björn Fromme 420efb25ad chore: update project dependencies 2025-12-09 12:56:31 +01:00
Björn Fromme 150998e120 fix: ensure flash message is displayed after redirect 2025-12-09 12:55:23 +01:00
Björn Fromme 31f414b4d8 feat: show room prices in room assignment form field 2025-12-09 12:55:00 +01:00
Björn Fromme 9c6860ecc6 fix: account for htmx issues in mobile safari with select fields 2025-12-09 11:42:31 +01:00
Björn Fromme 6b32b6baa4 fix: disable autocomplete in chrome for good 2025-12-09 11:33:19 +01:00
Björn Fromme 3527be9c29 feat: various improvements in styles and layout 2025-12-09 11:20:43 +01:00
Björn Fromme 0239aee89a fix: avoid stale caches 2025-12-09 10:25:11 +01:00
Björn Fromme f21f4a0385 feat: streamlined rendering of fields as static text in forms 2025-12-09 10:20:55 +01:00
Björn Fromme fa2b5e0d7f feat: render room assignment as radio buttons 2025-12-09 10:05:14 +01:00
Björn Fromme 1ac7720765 feat: replace overly complex and unnecessary form choice loader for rooms 2025-12-09 09:32:01 +01:00
Björn Fromme 4182c30b72 fix: ensure footer bar is visible on mobile safari 2025-12-09 09:21:58 +01:00
Björn Fromme e4aad8a456 feat: load cms data early to display image on login page 2025-12-08 17:39:29 +01:00
Björn Fromme d78638e6e5 feat: improved layout for participant form 2025-12-08 17:08:26 +01:00
Björn Fromme 1726523eaf fix: disable autocompletion on personal data fields 2025-12-08 16:20:20 +01:00
Björn Fromme 1aa564960d feat: body dimensions optional 2025-12-08 16:18:31 +01:00
Björn Fromme cd2765bab5 feat: improved error handling and redirect on invalid session 2025-12-08 16:00:02 +01:00
Björn Fromme 390ee81675 feat: indicate incomplete participant data in cards 2025-12-08 15:59:35 +01:00
Björn Fromme 6dbbfd87f8 feat: special treatment of services for participants of age 0-2 2025-12-08 15:26:30 +01:00
Björn Fromme 118f86b2a0 feat: increase availability cache ttl and ensure fresh data when entering form 2025-12-08 14:57:12 +01:00
Björn Fromme 27d77624da docs: upgrade plan to symfony 7.4 2025-12-07 18:48:40 +01:00
Björn Fromme 20a67e9b96 feat: optional return url 2025-12-07 18:47:18 +01:00
Björn Fromme 233748a6c5 chore: cleanup 2025-12-07 15:03:54 +01:00
Björn Fromme 67491a7f68 fix: remove obsolete htmx attributes from forms 2025-12-07 15:03:44 +01:00
Björn Fromme c7129d5791 chore: cleanup 2025-12-07 14:47:51 +01:00
Björn Fromme 4abee677f6 fix: enforce https 2025-12-07 14:24:08 +01:00
Björn Fromme 21600dc2d6 feat: implement hx-boost for reliable loading indication 2025-12-07 14:11:50 +01:00
Björn Fromme f0b84c9943 fix: ensure loading indicator is triggered 2025-12-06 18:13:38 +01:00
Björn Fromme 59418adc02 chore: update project dependencies 2025-12-06 15:05:06 +01:00
Björn Fromme de52907eec fix: remove form options cache causing issues 2025-12-06 15:02:34 +01:00
Björn Fromme bfb1a04ea0 feat: implement screendesign 2025-12-06 15:02:33 +01:00
Björn Fromme b206c3990b chore: update project dependencies 2025-12-06 15:02:13 +01:00
Björn Fromme 54a37c5bf7 feat: adjust loading indicator styles 2025-12-06 15:02:13 +01:00
Björn Fromme fa98ceac29 fix: add loading indicator to all 'back' buttons 2025-12-06 15:02:13 +01:00
Björn Fromme 1bab230f10 fix: consider mode in summary 2025-12-06 15:02:13 +01:00
Björn Fromme 5b55d0984a fix: correctly handle email uniqueness by excluding the applicant from validation 2025-12-06 15:02:13 +01:00
Björn Fromme 2b3a8f1c69 feat: request replay command for bpn api 2025-12-06 15:02:13 +01:00
Björn Fromme 696800aafd feat: refactoring and cleanup 2025-12-06 15:02:13 +01:00
Björn Fromme e7997f84eb fix: include user ini for adjusted php settings on prod host 2025-12-05 10:03:51 +01:00
Björn Fromme 8d3a7b99b4 fix: prevent type errors 2025-12-01 10:41:04 +01:00
Björn Fromme 61a8afdde7 fix: prevent null reference errors 2025-12-01 10:38:55 +01:00
Björn Fromme 1f3e79d57c fix: prevent null reference errors 2025-12-01 10:37:39 +01:00
Björn Fromme f4691ec67e feat: finalize voucher handling and discount display in summary and overview 2025-11-26 17:29:15 +01:00
Björn Fromme 32bef9a4e9 feat: special treatment of participants with age 0-2 (babies) 2025-11-26 15:38:49 +01:00
Björn Fromme 30704f936a fix: don't disable room selection field with single option 2025-11-25 18:14:33 +01:00
Björn Fromme 9167c84b4c fix: clear target path when canceling booking flow 2025-11-25 17:34:10 +01:00
Björn Fromme f5f5d43ab5 feat: conditionally render room assignment field in participant edit form 2025-11-25 17:30:23 +01:00
Björn Fromme 9b2ad3845d feat: prevent selection of baby rooms without regular rooms 2025-11-25 16:43:41 +01:00
Björn Fromme e2513d6245 chore: update claude settings 2025-11-25 16:43:05 +01:00
Björn Fromme 126fce9687 feat: step input for room type selection 2025-11-25 16:42:39 +01:00
Björn Fromme c1364a458b fix: correctly determine number of participants 2025-11-25 16:42:13 +01:00
Björn Fromme ecc4741f56 feat: correct determination of inquiry status and conditional voucher field display 2025-11-25 16:41:25 +01:00
Björn Fromme f33e55f201 feat: correct handling of vouchers 2025-11-24 10:20:21 +01:00
Björn Fromme ce1b9ece09 feat: layout improvements 2025-11-21 12:44:06 +01:00
Björn Fromme 9d28d2f102 feat: improved promotional and purchase vouchers 2025-11-21 12:43:51 +01:00
Björn Fromme aaa7e9f4c3 feat: promotional and purchase vouchers 2025-11-20 18:41:46 +01:00
Björn Fromme 26681e5c62 feat: fetch additional content from cms via api 2025-11-20 15:42:41 +01:00
Björn Fromme 33c3dc6022 feat: sort pickups by their times 2025-11-17 10:00:03 +01:00
Björn Fromme a6b0051f1b chore: update project dependencies 2025-11-17 09:51:13 +01:00
Björn Fromme d0d1edb3ae feat: sort pickups by their times 2025-11-17 09:50:00 +01:00
Björn Fromme 6e96f6fb44 fix: never validate insurance selection in edit mode 2025-11-13 12:44:19 +01:00
Björn Fromme c6b28e7f4e fix: don't validate insurance selection of participants when in bulk assignment 2025-11-13 12:29:27 +01:00
Björn Fromme 3ce4d81a4c chore: update project dependencies 2025-11-13 11:36:52 +01:00
Björn Fromme d5c572c25b feat: loading indicators for regular get requests 2025-11-13 11:34:45 +01:00
Björn Fromme bcded403be feat: improved timeout handling for api client 2025-11-13 11:15:31 +01:00
Björn Fromme aeb25f3b7e feat: remove 'remember me' functionality from login form in booking process 2025-11-13 10:54:40 +01:00
Björn Fromme 421851cc4c feat: surcharges and discounts per participant and in summary 2025-11-13 09:30:49 +01:00
Björn Fromme 66eb392151 fix: check field existence before rendering 2025-11-11 15:45:14 +01:00
Björn Fromme beaccd93e0 fix: show rental insurance field only when applicable 2025-11-11 15:39:56 +01:00
Björn Fromme 111cda95f3 chore: update project dependencies 2025-11-11 15:13:15 +01:00
Björn Fromme 84ed41f325 fix: tooltips for form fields not showing 2025-11-11 15:12:28 +01:00
Björn Fromme e7cf172b9f feat: add subtypes PAR and LVS as bookable additional services 2025-11-11 14:14:44 +01:00
Björn Fromme e52cb98163 chore: update project dependencies 2025-11-07 10:39:39 +01:00
Björn Fromme d85e81e8b9 fix: ensure valid applicant data 2025-11-07 10:39:16 +01:00
Björn Fromme 1e5fe23159 fix: don't rely on individual prices being available for all participants 2025-11-06 15:32:39 +01:00
Björn Fromme 2f78ddb8ad fix: don't rely on individual prices being available for all participants 2025-11-06 15:24:51 +01:00
Björn Fromme f19762d686 chore: update project dependencies 2025-11-06 14:55:23 +01:00
Björn Fromme eba2f8e503 fix: skip availability check for services that are not included in API response 2025-11-06 14:55:00 +01:00
Björn Fromme 0a0bef9e82 feat: ensure inquiry info is always visible 2025-10-31 16:40:14 +01:00
Björn Fromme 29f415a91f feat: improved dynamic validation 2025-10-31 16:23:06 +01:00
Björn Fromme a619add4e3 fix: ensure validation of participant data 2025-10-31 15:07:22 +01:00
Björn Fromme 34a8d42fc3 fix: keep browser history intact when navigating between cards view and participant form 2025-10-31 12:46:37 +01:00
Björn Fromme cfd346d5df wip: integrate with typo3 to fetch product and hotel data 2025-10-28 16:13:07 +01:00
Björn Fromme 3d694ed7eb fix: streamlined single room selection handling 2025-10-28 16:12:27 +01:00
Björn Fromme 5021f414d1 feat: improved mutability checks for personal data in edit or create mode 2025-10-28 15:34:09 +01:00
Björn Fromme 51dbf20118 feat: improved handling of fields to be rendered as static text 2025-10-27 13:38:40 +01:00
Björn Fromme a50bd205cd chore: update project dependencies 2025-10-27 08:33:59 +01:00
Björn Fromme da7b4dfb48 fix: temporarily disable all participant validation 2025-10-27 08:31:39 +01:00
Björn Fromme eee7be0c1e feat: gravatar integration 2025-10-25 14:09:19 +02:00
Björn Fromme d55a201681 feat: integrate with scheduler bundle 2025-10-24 17:57:13 +02:00
Björn Fromme ba0eab9e96 fix: adapt changes in create mode for edit mode, cleanup 2025-10-24 17:30:41 +02:00
Björn Fromme b63804df88 feat: authenticated booking 2025-10-24 17:07:08 +02:00
Björn Fromme 647a25a78f feat: performance improvements 2025-10-24 15:21:15 +02:00
Björn Fromme 6b0dfb3426 chore: fix deprecations in preparation uf upgrading to symfony 7.3 2025-10-24 13:59:54 +02:00
Björn Fromme c8bb051ae6 fix: incorrect and unnecessary template inheritance 2025-10-24 12:32:16 +02:00
Björn Fromme b326510b04 chore: consolidate documentation 2025-10-24 12:17:42 +02:00
Björn Fromme 293574187f feat: price info tooltip for bulk insurance booking
addresses #869axbjzz
2025-10-24 11:23:19 +02:00
Björn Fromme b74f84e8ad feat: rearrange field order
addresses #869axbhz3
2025-10-24 09:32:16 +02:00
Björn Fromme 19a272db96 feat: group rentals and rental insurance fields visually
addresses #869ay16cp
2025-10-24 09:28:41 +02:00
Björn Fromme 67843c2f2e feat: dedicated section for discounts in summary
addresses #869ay1724
2025-10-24 09:19:34 +02:00
Björn Fromme a01e966d6d feat: automatic unselection of discounted transportation 2025-10-24 09:04:20 +02:00
Björn Fromme 9140b97a71 fix: improved position of info icon 2025-10-23 11:54:44 +02:00
Björn Fromme 405f03ee7a fix: adopt wrapper dto to dynamic form field 2025-10-23 11:38:34 +02:00
Björn Fromme b88ad24c3d feat: display service descriptions as tooltip with info icon
addresses #869axbnj0
2025-10-23 11:07:47 +02:00
Björn Fromme bb630da5ed feat: remove room selection field entirely for single room type
addresses #869axcukn
2025-10-23 10:49:14 +02:00
Björn Fromme 39d944351c chore: cleanup, update documentation 2025-10-23 10:29:37 +02:00
Björn Fromme 2b272ef789 fix: validation error indication on cards 2025-10-23 10:19:18 +02:00
Björn Fromme 3e54a58b9b wip: email uniqueness validation 2025-10-23 09:29:27 +02:00
Björn Fromme 60176d19f4 wip: improved validation and feedback 2025-10-23 08:50:45 +02:00
Björn Fromme 9c716477aa feat: unique email addresses of participants unless child, cleanup
addresses #869axbn21
2025-10-22 17:42:17 +02:00
Björn Fromme be2fffad23 feat: additional conformation checkbox for terms and conditions
addresses #869axbm44
2025-10-22 16:19:05 +02:00
Björn Fromme 34230e5520 feat: improved layout for pickup selection to make price visible
addresses #869axbjmd
2025-10-22 16:01:17 +02:00
Björn Fromme 1949bf9b97 feat: prefer discounted transportation services
addresses #869axbjbz
2025-10-22 15:53:54 +02:00
Björn Fromme 7ab60b1048 feat: improved form field layout for date of birth 2025-10-22 10:37:20 +02:00
Björn Fromme 0e6c31b8ce feat: show placeholders for individual date parts in date of birth field 2025-10-22 10:10:02 +02:00
Björn Fromme a2cfb693e0 feat: replace date field for participant's birthday 2025-10-22 10:02:30 +02:00
Björn Fromme 10df3ebb35 wip: implement e2e tests with cypress 2025-10-21 20:25:18 +02:00
Björn Fromme ab91c138d5 feat: unassign rooms from other participants when unavailable 2025-10-21 17:02:26 +02:00
Björn Fromme cc1d1e5746 feat: automatically assign rooms only for unique room type selection 2025-10-20 15:29:33 +02:00
Björn Fromme 8c75d0070d chore: update project dependencies 2025-10-20 10:23:34 +02:00
Björn Fromme 4df04d0504 chore: cleanup, updated docs 2025-10-20 09:32:54 +02:00
Björn Fromme 38bc594ca4 feat: consolidated insurance service 2025-10-20 09:22:03 +02:00
Björn Fromme fb9c9d91ee feat: integrate with spatie/ray for debugging and performance optimization 2025-10-20 08:08:17 +02:00
Björn Fromme ee69346eb4 feat: extended pricing breakdown on confirmation page 2025-10-18 17:59:42 +02:00
Björn Fromme e6c47019d5 fix: fix floating point precision error 2025-10-18 17:44:24 +02:00
Björn Fromme b894bbf5e6 chore: update documentation 2025-10-18 17:17:49 +02:00
Björn Fromme 0f8fed605c chore: adjust and cleanup tests 2025-10-18 17:15:31 +02:00
Björn Fromme 479b177e90 wip: bulk insurance refactoring 2025-10-18 16:39:57 +02:00
Björn Fromme 08210b8e52 wip: bulk insurance booking fix 2025-10-18 13:07:27 +02:00
Björn Fromme b5dfe17b73 wip: finalize implementation 2025-10-18 12:11:24 +02:00
Björn Fromme 49b5ccf308 wip: finalize implementation 2025-10-18 11:46:12 +02:00
Björn Fromme 434c4d0a11 wip: finalize implementation 2025-10-17 18:46:25 +02:00
Björn Fromme dc7ed0728a feat: readonly room selection for single room types 2025-10-16 09:36:04 +02:00
Björn Fromme b1dbb15ad7 feat: display booked insurance in edit mode 2025-10-16 09:35:30 +02:00
Björn Fromme e76170b6dd chore: remove debug statements 2025-10-16 09:35:12 +02:00
Björn Fromme 8225d4e92d fix: show feedback modal 2025-10-16 09:12:43 +02:00
Björn Fromme a5addf8d33 fix: adopt changed template name 2025-10-15 21:29:12 +02:00
Björn Fromme 0542a669bd fix: adjust deployer config 2025-10-15 18:32:49 +02:00
Björn Fromme 49b7a3fe34 feat: refactor to cards 2025-10-15 18:31:10 +02:00
Björn Fromme ead2c092da fix: ensure skipass is selected 2025-10-15 11:40:51 +02:00
Björn Fromme 6e818c3480 wip: refactor to cards with individual participant forms 2025-10-14 21:27:32 +02:00
Björn Fromme a02490ea36 wip: add documentation for plan 2025-10-14 20:30:51 +02:00
Björn Fromme 9eda12981a feat: htmx powered requests, improved loading indicator
feat: loading indicator and htmx form submit
2025-10-14 18:07:59 +02:00
Björn Fromme 4939a1a9ad feat: inquiry bookings 2025-10-09 18:52:23 +02:00
Björn Fromme 989f599b54 chore: remove outdated documentation 2025-10-09 18:51:58 +02:00
Björn Fromme 67c642bc2f wip: modernized edit flow, fix insurance tier calculation 2025-10-09 17:42:39 +02:00
Björn Fromme cba0f747cd wip: modernized edit flow 2025-10-08 21:09:53 +02:00
Björn Fromme c3008d7f7a wip: insurance booking in edit flow 2025-10-07 18:09:16 +02:00
Björn Fromme 7304fb50c6 fix: set correct default agency 2025-10-07 17:27:26 +02:00
Björn Fromme ec1bba7c46 wip: backport booking create flow form handling to edit flow 2025-10-07 16:38:55 +02:00
Björn Fromme b66d453881 feat: unify pickup selection 2025-10-06 18:07:07 +02:00
Björn Fromme b7b80296e9 feat: comprehensive booking overview for confirmation 2025-10-06 16:43:55 +02:00
Björn Fromme 2f582f0548 fix: use correct country tokens 2025-10-06 15:58:44 +02:00
Björn Fromme fad28c2442 chore: update project dependencies 2025-10-06 11:22:42 +02:00
Björn Fromme 7f1ef4059d wip: submit booking to api 2025-10-06 11:22:02 +02:00
Björn Fromme 139ec3c1db wip: confirmation step 2025-10-05 13:46:19 +02:00
Björn Fromme 798beae597 feat: implement payment step 2025-10-05 13:29:19 +02:00
Björn Fromme 3edf5a80aa fix: don't submit data of removed fields 2025-10-04 18:08:11 +02:00
Björn Fromme fc93b28af0 wip: backport form handing system from create flow to edit flow 2025-10-04 12:12:16 +02:00
Björn Fromme cd82b70139 fix: ignore past travels in list view when patching data 2025-10-04 11:49:36 +02:00
Björn Fromme fba9edc931 feat: inform user about automatic reassignments or reset selections 2025-10-02 17:57:56 +02:00
Björn Fromme 8e43edcbaf feat: insurance info urls in tooltips 2025-10-02 17:28:53 +02:00
Björn Fromme 8984b2edd5 feat: customizable label for unavailable services 2025-10-02 16:56:37 +02:00
Björn Fromme 32ec2c1deb feat: make room selection fields read-only for single room type 2025-10-02 16:40:18 +02:00
Björn Fromme 25029dff5d feat: extended insurance parsing, pass info urls to view 2025-10-02 16:32:50 +02:00
Björn Fromme 875b181aff fix: filter rentals by skipass duration 2025-10-02 14:42:04 +02:00
Björn Fromme 0f3d9b87fa feat: auto-assign rooms 2025-10-02 12:25:42 +02:00
Björn Fromme d7929dd855 wip: improved insurance selection 2025-10-02 12:11:23 +02:00
Björn Fromme 8a495346d6 wip: check eligibility based on ski pass availability 2025-10-01 18:52:50 +02:00
Björn Fromme fef4997132 chore: update docs 2025-10-01 17:57:39 +02:00
Björn Fromme b4eaf695c7 feat: bulk insurance booking by applicant 2025-10-01 17:52:21 +02:00
Björn Fromme 372490ed5a feat: improved form layout 2025-09-30 17:11:30 +02:00
Björn Fromme e37b6234e8 chore: remove debugging statements 2025-09-30 16:47:29 +02:00
Björn Fromme 71b42786f7 feat: show room pricing details 2025-09-30 16:47:17 +02:00
Björn Fromme 009eabd09c fix: layout improvements 2025-09-30 16:08:59 +02:00
Björn Fromme 49a4393980 fix: consider participant's age at travel date 2025-09-30 16:08:20 +02:00
Björn Fromme c0e20a15fe fix: ensure mandatory services are selected 2025-09-30 16:08:02 +02:00
Björn Fromme 061317ed4c wip: insurance booking 2025-09-30 15:13:20 +02:00
Björn Fromme a5dce776de wip: insurance booking 2025-09-30 14:37:49 +02:00
Björn Fromme 90ae78262a wip: insurance booking 2025-09-29 19:54:20 +02:00
Björn Fromme 0809f07d46 wip: insurance booking phase 5 2025-09-26 16:54:48 +02:00
Björn Fromme 199ef08e35 wip: insurance booking phase 4 2025-09-26 16:48:48 +02:00
Björn Fromme 4930a2ba42 wip: insurance booking phase 3 2025-09-26 16:46:04 +02:00
Björn Fromme 0ceabe465b wip: insurance booking phases 1 and 2 2025-09-26 16:34:32 +02:00
Björn Fromme bd7b70e465 feat: correct calculation and display of individual pricing 2025-09-26 15:32:22 +02:00
Björn Fromme 55a24b99f0 chore: update project dependencies 2025-09-26 09:01:32 +02:00
Björn Fromme 122df1a3f5 feat: improved error handling in controllers, cleanup 2025-09-26 09:00:40 +02:00
Björn Fromme 391dd63ebf feat: improved error handling of xml parsers and loaders 2025-09-26 08:21:57 +02:00
Björn Fromme 9d44197246 feat: parser and loader for insurance data 2025-09-24 15:28:43 +02:00
Björn Fromme 582fb9b52d feat: functionality to determine family status of a booking 2025-09-24 12:58:42 +02:00
Björn Fromme eed7ba4d7b feat: prevent booking flow without available rooms 2025-09-24 11:14:45 +02:00
Björn Fromme 5642193610 feat: validate room selection 2025-09-24 10:59:23 +02:00
Björn Fromme 1a1e120cf6 feat: render tooltips 2025-09-24 10:44:01 +02:00
Björn Fromme cf66b85993 feat: streamlined tooltip data attributes 2025-09-24 10:30:14 +02:00
Björn Fromme 8677e9a8a5 chore: update project dependencies 2025-09-22 17:37:11 +02:00
Björn Fromme 906f591979 feat: mark unavailable services as read-only and add tooltip 2025-09-22 17:36:49 +02:00
Björn Fromme 97cc0ac422 feat: simplify validation 2025-09-19 16:37:48 +02:00
Björn Fromme bdc7100f74 feat: simplify handling of ski pass service 2025-09-19 16:19:01 +02:00
Björn Fromme 29a51ed66d feat: cached api results for availabilities 2025-09-19 16:09:41 +02:00
Björn Fromme c9a258a350 chore: streamline property naming 2025-09-19 16:09:27 +02:00
Björn Fromme 096dd96db0 feat: enrich travel data with live availabilities 2025-09-19 12:40:20 +02:00
Björn Fromme ddd5971c06 feat: replace xss extension with symfony component 2025-09-19 12:40:02 +02:00
Björn Fromme b7638f5e9e fix: use correct ids for user validation 2025-09-10 16:26:58 +02:00
Björn Fromme b197152f12 feat: restrict access to booking edit and invoice to applicant 2025-09-10 15:30:36 +02:00
Björn Fromme 297becf7a0 fix: filter selectable services by participant's age 2025-09-10 15:25:30 +02:00
Björn Fromme b6f991b291 wip: skipass-duration based rentals filtering 2025-09-10 14:26:18 +02:00
Björn Fromme 5469c834a6 wip: transportation services with discount 2025-09-10 14:08:44 +02:00
Björn Fromme a3ea02a136 wip: service descriptions and car license plate field 2025-09-10 12:53:33 +02:00
Björn Fromme 195246af89 wip: rentals insurance field 2025-09-03 17:54:19 +02:00
Björn Fromme 2953ed0b2d wip: improved refresh logic 2025-09-03 16:48:23 +02:00
Björn Fromme ccb2fa75ac wip: transportation services in summary 2025-09-03 14:58:24 +02:00
Björn Fromme a33e6a0dd4 wip: update documentation 2025-09-02 20:09:29 +02:00
Björn Fromme 435e3a79e8 wip: dynamic availability of services 2025-09-02 20:03:22 +02:00
Björn Fromme 21054f0c45 wip: implement transportation, pickups and parking 2025-09-02 19:32:02 +02:00
Björn Fromme 605b6ca64c wip: transportation services 2025-09-02 18:28:51 +02:00
Björn Fromme bc9616e7de wip: prepare transportation services 2025-09-02 17:52:42 +02:00
Björn Fromme 491169b9d7 wip: update docs 2025-09-02 17:21:50 +02:00
Björn Fromme 0e0ce254a9 wip: show pricing 2025-09-02 16:59:55 +02:00
Björn Fromme 7b25fbf28b chore: adjust schedule for XML cleanup to run more often 2025-09-02 09:29:36 +02:00
Björn Fromme 2a5100e76d feat: update scheduler config 2025-09-02 08:51:12 +02:00
Björn Fromme e98695ea06 feat: integrate with zenstruck schedule bundle 2025-09-02 08:47:57 +02:00
Björn Fromme 1c2421fb7e fix: respect environment variable to toggle BPN debug mode 2025-09-02 08:40:17 +02:00
Björn Fromme 76aeb101bd chore: update project dependencies 2025-09-02 08:29:22 +02:00
Björn Fromme 60b655a195 wip: dynamic services fields 2025-08-27 17:49:49 +02:00
Björn Fromme 369d660e24 wip: age based filtering of options 2025-08-27 15:02:45 +02:00
Björn Fromme 47703dc205 wip: age based filtering of options 2025-08-27 13:46:00 +02:00
Björn Fromme 25bbf3d44f wip: age based filtering of options 2025-08-27 12:42:02 +02:00
Björn Fromme 803b10f981 chore: update project dependencies 2025-08-27 10:00:01 +02:00
Björn Fromme b992e4a5ea wip: conditional mandatory body dimensions 2025-07-25 21:47:00 +02:00
Björn Fromme 9c5597eb23 wip: additional services with constraints 2025-07-25 18:12:55 +02:00
Björn Fromme 2ec61d5086 wip: courses 2025-07-25 16:53:48 +02:00
Björn Fromme 8bae958e24 wip: booking process 2025-07-25 15:47:11 +02:00
Björn Fromme e7f0c09b36 wip: major refactoring 2025-07-25 11:54:07 +02:00
Björn Fromme ae2ed306b9 wip: form refactoring 2025-07-25 09:28:13 +02:00
Björn Fromme 2b122a7cc4 wip: improved booking summary 2025-07-24 12:44:38 +02:00
Björn Fromme 787e76c21c wip: refactor 2025-07-24 11:59:40 +02:00
Björn Fromme 7b1f2e7468 wip: booking summary for step 1 2025-07-24 11:59:27 +02:00
Björn Fromme 3f94c51bc8 wip: refactor 2025-07-24 11:12:06 +02:00
Björn Fromme 64d51c01b2 wip: refactor 2025-07-24 10:03:02 +02:00
Björn Fromme 955dbd2f05 fix: correct handling of readonly checkboxes with tooltips 2025-07-24 09:33:27 +02:00
Björn Fromme 318a326fdb chore: update browserslist 2025-07-24 09:33:05 +02:00
Björn Fromme 86223dc8a6 wip: field states and dependencies 2025-07-23 18:38:31 +02:00
Björn Fromme 4bb62830a4 wip: refactor forms 2025-07-23 18:10:27 +02:00
Björn Fromme 4ce731bfcb wip: refactor forms 2025-07-23 17:15:39 +02:00
Björn Fromme f225dac5fe wip: collapsible forms 2025-07-23 15:48:59 +02:00
Björn Fromme 5e1f2a8711 wip: refactor forms 2025-07-23 15:34:54 +02:00
Björn Fromme 8746397d83 wip: feedback about booked and assigned rooms 2025-07-23 11:39:03 +02:00
Björn Fromme e8c27cb51b wip: refactoring 2025-07-23 11:08:29 +02:00
Björn Fromme d2a80ea8fd wip: refactoring 2025-07-23 10:28:38 +02:00
Björn Fromme c85c72863c wip: refactoring 2025-07-23 10:27:04 +02:00
Björn Fromme 77afc0fe7b Merge branch 'master' into booking 2025-07-22 09:03:38 +02:00
Björn Fromme 7a53908b80 chore: update deployer config with extended rsync excludes 2025-07-22 09:02:47 +02:00
Björn Fromme ca4495169f Merge branch 'master' into booking 2025-07-22 08:59:19 +02:00
Björn Fromme d1344bbfb4 chore: remove project name from ddev config to enable git worktrees 2025-07-22 08:58:44 +02:00
810 changed files with 11792 additions and 94824 deletions

No files matched your search

@@ -0,0 +1,11 @@
name: opencode
repository: /Users/fromme/Development/Misc/ddev-opencode
version: ""
install_date: "2026-01-05T17:21:57+01:00"
project_files:
- web-build/Dockerfile.opencode
- commands/web/opencode
- config.opencode.yaml
- opencode/.gitignore
global_files: []
removal_actions: []
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
#ddev-generated
## Description: OpenCode AI coding assistant
## Usage: opencode
## Example: ddev opencode [...]
set -e
opencode $@
+6
View File
@@ -0,0 +1,6 @@
#ddev-generated
webimage_extra_packages:
- xdg-utils
hooks:
post-start:
- exec: "mkdir -p /var/www/html/.ddev/opencode/.opencode && ln -sf /var/www/html/.ddev/opencode/.opencode ~/.opencode"
+24 -40
View File
@@ -1,51 +1,44 @@
type: php
docroot: public
php_version: "8.3"
php_version: "8.2"
webserver_type: apache-fpm
xdebug_enabled: false
additional_hostnames:
- mysnz
- mysbw
- myser
additional_hostnames: []
additional_fqdns: []
database:
type: mysql
version: "8.4"
type: mariadb
version: "10.11"
use_dns_when_possible: true
composer_version: "2"
web_environment: []
corepack_enable: false
nodejs_version: "22"
# Key features of DDEV's config.yaml:
# name: <projectname> # Name of the project, automatically provides
# http://projectname.ddev.site and https://projectname.ddev.site
# If the name is omitted, the project will take the name of the enclosing directory,
# which is useful if you want to have a copy of the project side by side with this one.
# type: <projecttype> # backdrop, cakephp, craftcms, drupal, drupal6, drupal7, drupal8, drupal9, drupal10, drupal11, generic, laravel, magento, magento2, php, shopware6, silverstripe, symfony, typo3, wordpress
# See https://docs.ddev.com/en/stable/users/quickstart/ for more
# type: <projecttype> # backdrop, craftcms, django4, drupal, drupal6, drupal7, laravel, magento, magento2, php, python, shopware6, silverstripe, typo3, wordpress
# See https://ddev.readthedocs.io/en/stable/users/quickstart/ for more
# information on the different project types
# "drupal" covers recent Drupal 8+
# docroot: <relative_path> # Relative path to the directory containing index.php.
# php_version: "8.3" # PHP version to use, "5.6" through "8.5"
# php_version: "8.2" # PHP version to use, "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"
# You can explicitly specify the webimage but this
# is not recommended, as the images are often closely tied to DDEV's' behavior,
# so this can break upgrades.
# webimage: <docker_image>
# It’s unusual to change this option, and we don’t recommend it without Docker experience and a good reason.
# Typically, this means additions to the existing web image using a .ddev/web-build/Dockerfile.*
# webimage: <docker_image> # nginx/php docker image.
# database:
# type: <dbtype> # mysql, mariadb, postgres
# version: <version> # database version, like "10.11" or "8.0"
# MariaDB versions can be 5.5-10.8, 10.11, 11.4, 11.8
# MySQL versions can be 5.5-8.0, 8.4
# PostgreSQL versions can be 9-18
# MariaDB versions can be 5.5-10.8, 10.11, and 11.4.
# MySQL versions can be 5.5-8.0.
# PostgreSQL versions can be 9-17.
# router_http_port: <port> # Port to be used for http (defaults to global configuration, usually 80)
# router_https_port: <port> # Port for https (defaults to global configuration, usually 443)
@@ -55,21 +48,12 @@ nodejs_version: "22"
# "ddev xdebug" to enable Xdebug and "ddev xdebug off" to disable it work better,
# as leaving Xdebug enabled all the time is a big performance hit.
# xhgui_http_port: "8143"
# xhgui_https_port: "8142"
# The XHGui ports can be changed from the default 8143 and 8142
# Very rarely used
# xhprof_enabled: false # Set to true to enable Xhprof and "ddev start" or "ddev restart"
# Note that for most people the commands
# "ddev xhprof" to enable Xhprof and "ddev xhprof off" to disable it work better,
# as leaving Xhprof enabled all the time is a big performance hit.
# host_xhgui_port: "8142"
# Can be used to change the host binding port of the XHGui
# application. Rarely used; only when port conflict and
# bind_all_ports is used (normally with router disabled)
# xhprof_mode: [prepend|xhgui|global]
# Set to "xhgui" to enable XHGui features
# "xhgui" will become default in a future major release
# webserver_type: nginx-fpm, apache-fpm, generic
# webserver_type: nginx-fpm, apache-fpm, or nginx-gunicorn
# timezone: Europe/Berlin
# If timezone is unset, DDEV will attempt to derive it from the host system timezone
@@ -95,9 +79,9 @@ nodejs_version: "22"
# Alternatively, an explicit Composer version may be specified, for example "2.2.18".
# To reinstall Composer after the image was built, run "ddev debug rebuild".
# nodejs_version: "22"
# nodejs_version: "20"
# change from the default system Node.js version to any other version.
# See https://docs.ddev.com/en/stable/users/configuration/config/#nodejs_version for more information
# See https://ddev.readthedocs.io/en/stable/users/configuration/config/#nodejs_version for more information
# and https://www.npmjs.com/package/n#specifying-nodejs-versions for the full documentation,
# Note that using of 'ddev nvm' is discouraged because "nodejs_version" is much easier to use,
# can specify any version, and is more robust than using 'nvm'.
@@ -133,7 +117,7 @@ nodejs_version: "22"
# ddev_version_constraint: ""
# Example:
# ddev_version_constraint: ">= 1.24.8"
# ddev_version_constraint: ">= 1.22.4"
# This will enforce that the running ddev version is within this constraint.
# See https://github.com/Masterminds/semver#checking-version-constraints for
# supported constraint formats
@@ -162,8 +146,8 @@ nodejs_version: "22"
# - "mutagen": enables Mutagen for this project.
# - "nfs": enables NFS for this project.
#
# See https://docs.ddev.com/en/stable/users/install/performance/#nfs
# See https://docs.ddev.com/en/stable/users/install/performance/#mutagen
# See https://ddev.readthedocs.io/en/stable/users/install/performance/#nfs
# See https://ddev.readthedocs.io/en/stable/users/install/performance/#mutagen
# fail_on_hook_fail: False
# Decide whether 'ddev start' should be interrupted by a failing hook
@@ -212,7 +196,7 @@ nodejs_version: "22"
# ngrok_args: --basic-auth username:pass1234
# Provide extra flags to the "ngrok http" command, see
# https://ngrok.com/docs/agent/config/v3/#agent-configuration or run "ngrok http -h"
# https://ngrok.com/docs/ngrok-agent/config or run "ngrok http -h"
# disable_settings_management: false
# If true, DDEV will not create CMS-specific settings files like
@@ -290,7 +274,7 @@ nodejs_version: "22"
# Many DDEV commands can be extended to run tasks before or after the
# DDEV command is executed, for example "post-start", "post-import-db",
# "pre-composer", "post-composer"
# See https://docs.ddev.com/en/stable/users/extend/custom-commands/ for more
# See https://ddev.readthedocs.io/en/stable/users/extend/custom-commands/ for more
# information on the commands that can be extended and the tasks you can define
# for them. Example:
#hooks:
+5
View File
@@ -0,0 +1,5 @@
#ddev-generated
# OpenCode internal config
/.opencode/
+4
View File
@@ -0,0 +1,4 @@
#ddev-generated
RUN npm install -g opencode-ai
+3 -55
View File
@@ -25,7 +25,7 @@ APP_SECRET=642ead390b8a38f0a017ec84d5362129
#
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
# DATABASE_URL="mysql://app:[email protected]:3306/app?serverVersion=8.0.32&charset=utf8mb4"
DATABASE_URL="mysql://db:db@db:3306/db?serverVersion=8.4.0&charset=utf8mb4"
DATABASE_URL="mysql://db:db@db:3306/db?serverVersion=10.11.11-MariaDB&charset=utf8mb4"
# DATABASE_URL="postgresql://app:[email protected]:5432/app?serverVersion=16&charset=utf8"
###< doctrine/doctrine-bundle ###
@@ -40,73 +40,26 @@ MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
MAILER_DSN=null://null
###< symfony/mailer ###
MAILJET_API_KEY=
MAILJET_API_SECRET=
MAILJET_API_BASE_URL=https://api.mailjet.com/v3/REST
MAILJET_DEFAULT_LIST_ID=
# Development default for HTTP Basic Auth password; override in production secrets.
MAILJET_WEBHOOK_BASIC_PASSWORD=secret
APP_NEWSLETTER_CONFIRMATION_TTL_HOURS=1
# Dedicated signing secret for accommodation booking customer access links (kept separate
# from APP_SECRET so it can be rotated independently). Unlike lazily-used API keys, UriSigner
# validates this is non-empty at construction time, so a real dev value is required here
# (override in .env.local/production secrets as usual).
ACCOMMODATION_OFFER_LINK_SECRET=abf8ec28cc2162d9121d35d6f8cbf7c29728cdacce0303e22e1bac854501728a
ACCOMMODATION_TERMS_AT=
ACCOMMODATION_TERMS_CH=
ACCOMMODATION_TERMS_IT=
BPN_CONNECT_BASE_URL=https://bpn-connect.ep-reisen.app
BPN_CONNECT_API_KEY=
APP_BPN_USER=
APP_BPN_PASSWORD=
APP_BPN_IP=
APP_BPN_PORTS=
APP_BPN_PORT=
APP_BPN_DEBUG=false
APP_BPN_CONNECTION_TIMEOUT=5
APP_BPN_STREAM_TIMEOUT=30
APP_BPN_TOTAL_TIMEOUT=45
APP_TRAVEL_INFO_BASE_URL="https://www.ep-reisen.de/reiseinformationen/"
APP_LEGAL_NOTICE_URL="https://www.ep-reisen.de/unternehmen/impressum-skireiseveranstalter/"
APP_TERMS_AND_CONDITIONS_URL="https://www.ep-reisen.de/skireisen/infos/allgemeine-infos/agb/"
APP_PRIVACY_POLICY_URL="https://www.ep-reisen.de/unternehmen/impressum-skireiseveranstalter/datenschutz-winterreisen/"
APP_CMS_API_BASE_URL="https://www.ep-reisen.de/"
APP_WEBSITE_BASE_URL="https://www.ep-reisen.de/"
APP_BASE_URL="https://my.ep-reisen.de"
APP_CUSTOMER_SERVICE_EMAIL="[email protected]"
APP_INSURANCE_REVOCATION_URL="https://www.hmrv.de/daten-aendern/vertrag-beenden/widerruf"
# Travel Data Service Configuration
APP_TRAVEL_PREFER_REMOTE=false
APP_TRAVEL_ENABLE_FALLBACK=true
APP_TRAVEL_SNAPSHOT_RETENTION_BUFFER_DAYS=14
# Emails
APP_DEFAULT_EMAIL_FROM=[email protected]
APP_DEFAULT_EMAIL_TO=[email protected]
ACCOMMODATION_INQUIRY_EMAIL=[email protected]
# Global common defaults
APP_SEASON_WINTER_FROM=2026-10-01
APP_SEASON_SUMMER_FROM=2026-05-01
APP_RUNNING_COSTS_FACTOR_EUR=2.75
APP_RUNNING_COSTS_FACTOR_CHF=3.2
APP_UNDERSUBSCRIPTION_SURCHARGE_30_EUR=5.0
APP_UNDERSUBSCRIPTION_SURCHARGE_30_CHF=5.0
APP_UNDERSUBSCRIPTION_SURCHARGE_40_EUR=2.5
APP_UNDERSUBSCRIPTION_SURCHARGE_40_CHF=2.5
# Booking Configuration
# Status for new bookings: 'F' (Fixed/Final), 'O' (Option - requires agency confirmation)
# Use 'O' during beta phase, switch to 'F' for production
DEFAULT_BOOKING_STATUS=F
API_KEYS=
XML_EXPORT_PATH="%kernel.project_dir%/var/xmlexport"
XML_EXPORT_CONTINGENTS_PATH="%kernel.project_dir%/var/xmlexportzimmer"
JSON_EXPORT_PATH="%kernel.project_dir%/var/jsonexport"
SFTP_XML_EXPORT_HOST=
@@ -114,11 +67,6 @@ SFTP_XML_EXPORT_PORT=
SFTP_XML_EXPORT_USER=
SFTP_XML_EXPORT_PASSWORD=
SFTP_XML_EXPORT_CONTINGENTS_HOST=
SFTP_XML_EXPORT_CONTINGENTS_PORT=
SFTP_XML_EXPORT_CONTINGENTS_USER=
SFTP_XML_EXPORT_CONTINGENTS_PASSWORD=
###> league/oauth2-server-bundle ###
OAUTH_PRIVATE_KEY=%kernel.project_dir%/config/secret/private.key
OAUTH_PUBLIC_KEY=%kernel.project_dir%/config/secret/public.key
-1
View File
@@ -4,4 +4,3 @@ APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999
PANTHER_APP_ENV=panther
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
MAILJET_WEBHOOK_BASIC_PASSWORD=secret
-6
View File
@@ -31,9 +31,3 @@ yarn-error.log
/.php-cs-fixer.php
/.php-cs-fixer.cache
###< friendsofphp/php-cs-fixer ###
/ray.php
###> phpstan/phpstan ###
phpstan.neon
###< phpstan/phpstan ###
+10 -51
View File
@@ -60,7 +60,7 @@ Authorization: Bearer {{$auth.token("oauth2_api")}}
### API travel
# @no-cookie-jar
GET {{base_url}}/api/travels/DPWMP140326
GET {{base_url}}/api/travels/SBW131225
Accept: application/json
Authorization: Bearer {{$auth.token("oauth2_api")}}
@@ -72,7 +72,7 @@ Authorization: Bearer {{$auth.token("oauth2_api")}}
### API hotel availability remote
# @no-cookie-jar
GET {{base_url}}/api/travels/11606/152546/2026-01-24/availability
GET {{base_url}}/api/travels/11603/152546/2026-01-03/availability
Accept: application/json
Authorization: Bearer {{$auth.token("oauth2_api")}}
@@ -90,50 +90,16 @@ Content-Type: application/json
Authorization: Bearer {{$auth.token("oauth2_api")}}
{
"lastName": "{{$random.name.lastName}}",
"firstName": "{{$random.name.firstName}}",
"gender": "d",
"street": "{{$random.address.streetAddress}}",
"zipCode": "{{$random.address.zipCode}}",
"city": "{{$random.address.city}}",
"email": "{{$random.email}}",
"phone": "{{$random.phoneNumber.cellPhone}}"
"lastName": "Duschen",
"firstName": "Isolde",
"gender": "f",
"street": "Fooroad 1",
"zipCode": "12345",
"city": "Bartown",
"email": "[email protected]",
"phone": "12345"
}
### API newsletter lists map
# @no-cookie-jar
GET {{base_url}}/api/newsletters
Accept: application/json
Content-Type: application/json
Authorization: Bearer {{$auth.token("oauth2_newsletter")}}
### API newsletter subscriptions
# @no-cookie-jar
POST {{base_url}}/api/newsletter-subscriptions
Accept: application/json
Content-Type: application/json
Authorization: Bearer {{$auth.token("oauth2_newsletter")}}
{
"email": "{{$random.email}}",
"firstName": "{{$random.address.firstName}}",
"lastName": "{{$random.address.lastName}}",
"listIds": [10321569,10321382,10321383]
}
### API contingent calendar
# @no-cookie-jar
GET {{base_url}}/api/contingents/calendar?hotelCode=DGS&dateFrom=2026-06-01&dateTo=2026-06-30
Accept: application/json
Authorization: Bearer {{$auth.token("oauth2_api")}}
### API contintent prices
# @no-cookie-jar
GET {{base_url}}/api/contingents/prices?hotelCode=DGS&year=2026
Accept: application/json
Content-Type: application/json
Authorization: Bearer {{$auth.token("oauth2_api")}}
### API pickups planning webhook
# @no-cookie-jar
POST {{base_url}}/api/pickups-planning
@@ -149,10 +115,3 @@ GET {{base_url}}/api/pickups-planning/DPWWTS191125
Accept: application/json
Content-Type: application/json
Authorization: Bearer {{$auth.token("oauth2_api")}}
### API accommodation booking
# @no-cookie-jar
GET {{base_url}}/api/accommodation-bookings/e4591076-eb65-41e8-a115-09d18d15604a
Accept: application/json
Content-Type: application/json
Authorization: Bearer {{$auth.token("oauth2_api")}}
-8
View File
@@ -1,8 +0,0 @@
import htmx from 'htmx.org'
htmx.config.includeIndicatorStyles = false
htmx.config.historyCacheSize = 0
htmx.config.allowScriptTags = false
import './bootstrap.js'
import './styles/admin.css'
-9
View File
@@ -13,12 +13,3 @@ htmx.config.allowScriptTags = false
htmx.config.withCredentials = true
htmx.config.selfRequestsOnly = false
htmx.config.timeout = 50000 // 50 seconds - slightly higher than backend timeout (45s)
document.body.addEventListener('htmx:beforeSwap', (event) => {
// Symfony renders invalid forms with 422; let HTMX swap those responses so inline
// validation errors are actually shown to the user.
if (event.detail?.xhr?.status === 422) {
event.detail.shouldSwap = true
event.detail.isError = false
}
})
@@ -1,84 +0,0 @@
import { Controller } from '@hotwired/stimulus'
import { useFetch } from '../mixins/use_fetch'
import Autocomplete from '@trevoreyre/autocomplete-js'
export default class extends Controller {
static targets = [ 'input', 'field', 'resetButton', 'searchIcon' ]
static values = { url: String, choices: Array, selected: Boolean }
initialize() {
useFetch(this)
}
connect() {
const searchHandler = input => {
return new Promise(resolve => {
// Check input minimum length
if (input.length < 2) {
return resolve([])
}
// Search choices if provided
if (this.choicesValue.length > 0) {
return resolve(this.choicesValue.filter(choice => {
return -1 !== choice.text.toLowerCase().search(input.toLowerCase())
}))
}
// Use API otherwise
let data = { search: input }
fetch(this.urlValue, { method: 'POST', body: JSON.stringify(data), credentials: 'include' })
.then(this.checkStatus)
.then(this.parseJSON)
.then(data => {
resolve(data)
})
})
}
const submitHandler = result => {
this.fieldTarget.value = result.value
this.selectedValue = true
this.element.dispatchEvent(new CustomEvent('select', {
detail: { result }
}))
}
this.autocomplete = new Autocomplete(this.element, {
search: searchHandler,
getResultValue: result => result.text,
submitOnEnter: true,
onSubmit: submitHandler,
debounceTime: 250,
})
if (this.fieldTarget.value) {
this.selectedValue = true
}
// prevent form submission when selecting entry in autocomplete list with enter key
this.element.addEventListener('keypress', e => {
if (e.key === 'Enter') {
e.preventDefault()
}
})
}
reset() {
this.inputTarget.value = null
this.fieldTarget.value = null
this.selectedValue = false
this.element.dispatchEvent(new CustomEvent('reset'))
}
selectedValueChanged() {
this.resetButtonTarget.classList.toggle('hidden', false === this.selectedValue)
this.searchIconTarget.classList.toggle('hidden', this.selectedValue)
}
disconnect() {
this.autocomplete.destroy()
}
}
-59
View File
@@ -1,59 +0,0 @@
import { Controller } from '@hotwired/stimulus'
/**
* Monitors birthday input fields (day, month, year) and dispatches a custom event
* only when all three fields are filled with valid values.
*
* This prevents premature HTMX refreshes when users are still entering the date,
* improving UX by waiting until the complete date is entered.
*/
export default class extends Controller {
static targets = ['day', 'month', 'year']
/**
* Checks if all birthday fields are filled and dispatches a completion event.
*
* Called on input/change events from the day, month, and year fields.
* Only dispatches the 'birthday:complete' event when all three fields
* contain valid values that could form a complete date.
*/
check() {
const day = this.dayTarget.value.trim()
const month = this.monthTarget.value.trim()
const year = this.yearTarget.value.trim()
if (false === this.isComplete(day, month, year)) {
return
}
this.element.dispatchEvent(new CustomEvent('birthday:complete', { bubbles: true }))
}
/**
* Validates that all date components are filled with plausible values.
*
* @param {string} day The day value
* @param {string} month The month value
* @param {string} year The year value
*
* @returns {boolean} True if all fields contain complete values
*/
isComplete(day, month, year) {
// Day: 1-2 digits
if (0 === day.length || day.length > 2) {
return false
}
// Month: 1-2 digits
if (0 === month.length || month.length > 2) {
return false
}
// Year: exactly 4 digits for a complete year
if (4 !== year.length) {
return false
}
return true
}
}
@@ -1,37 +0,0 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static values = {
content: String,
label: String,
}
connect() {
this.originalLabel = this.element.innerText
}
disconnect() {
clearTimeout(this.resetTimer)
}
copy() {
navigator.clipboard.writeText(this.contentValue).then(() => {
this.dispatch('copied', {
detail: {
content: this.contentValue,
}
})
}).catch((error) => {
console.error('Failed to copy to clipboard:', error)
})
if (this.hasLabelValue) {
this.element.innerText = this.labelValue
clearTimeout(this.resetTimer)
this.resetTimer = setTimeout(() => {
this.element.innerText = this.originalLabel
}, 3000)
}
}
}
@@ -1,13 +0,0 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static values = {
payload: Object
};
connect() {
if (typeof window.dataLayer !== 'undefined') {
window.dataLayer.push(this.payloadValue);
}
}
}
@@ -1,70 +0,0 @@
import { Controller } from '@hotwired/stimulus'
import { Calendar } from 'vanilla-calendar-pro'
/* stimulusFetch: 'lazy' */
export default class extends Controller {
static targets = ['field', 'hiddenField']
static values = {
minDate: String,
maxDate: String,
disableWeekends: Boolean,
disabledDates: Array,
}
connect() {
const options = {
inputMode: true,
locale: 'de-DE',
selectedTheme: 'light',
selectedDates: this.hiddenFieldTarget.value ? [this.hiddenFieldTarget.value] : [],
onClickDate: (self) => {
const iso = self.context.selectedDates[0] ?? null
this.hiddenFieldTarget.value = iso ?? ''
if (iso) {
const [year, month, day] = iso.split('-')
this.fieldTarget.value = `${day}.${month}.${year}`
} else {
this.fieldTarget.value = ''
}
this.element.dispatchEvent(new CustomEvent('datepicker:picked', {
detail: { date: this.fieldTarget.value }
}))
},
onHide: () => {
this.element.dispatchEvent(new CustomEvent('datepicker:closed'))
},
}
if (this.minDateValue) options.dateMin = this.minDateValue
if (this.maxDateValue) options.dateMax = this.maxDateValue
if (this.disableWeekendsValue) options.disableWeekdays = [0, 6]
if (this.disabledDatesValue.length) options.disableDates = this.disabledDatesValue
this.picker = new Calendar(this.fieldTarget, options)
this.picker.init()
this.handleManualInput = () => {
const value = this.fieldTarget.value.trim()
if (!value) {
this.hiddenFieldTarget.value = ''
this.picker.set({ selectedDates: [] }, { dates: true })
} else {
const match = value.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/)
if (match) {
const [, day, month, year] = match
const iso = `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
this.hiddenFieldTarget.value = iso
this.picker.set({ selectedDates: [iso] }, { dates: true })
}
}
this.element.dispatchEvent(new CustomEvent('datepicker:closed'))
}
this.fieldTarget.addEventListener('change', this.handleManualInput)
}
disconnect() {
this.fieldTarget.removeEventListener('change', this.handleManualInput)
this.picker.destroy()
}
}
-29
View File
@@ -1,29 +0,0 @@
import { Controller } from '@hotwired/stimulus'
import GLightbox from 'glightbox'
/* stimulusFetch: 'lazy' */
export default class extends Controller {
static targets = ['item']
connect() {
this.lightbox = GLightbox({
elements: this.itemTargets.map((el) => ({
href: el.dataset.galleryHref,
type: 'image',
alt: el.dataset.galleryAlt ?? '',
})),
})
this.itemTargets.forEach((el, index) => {
el.addEventListener('click', (e) => {
e.preventDefault()
this.lightbox.openAt(index)
})
})
}
disconnect() {
this.lightbox.destroy()
}
}
@@ -1,16 +0,0 @@
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
static outlets = [ 'mobilenav' ]
static classes = [ 'closed' ]
trigger({ params: { mode } }) {
this.mobilenavOutlet.toggle(mode)
}
toggle(mode) {
// Add animation classes only now to avoid fouc
this.element.classList.add('transition-transform', 'duration-300')
this.element.classList.toggle(this.closedClass, 'close' === mode)
}
}
@@ -1,36 +0,0 @@
import { Controller } from '@hotwired/stimulus'
import { useClickOutside } from 'stimulus-use'
export default class extends Controller {
static targets = [ 'label', 'dropdown', 'choice' ]
static values = { placeholder: String }
connect() {
this.update()
useClickOutside(this)
}
toggle() {
this.dropdownTarget.classList.toggle('hidden')
}
update() {
let labels = []
this.choiceTargets.forEach((choice) => {
if (choice.checked) {
labels.push(choice.dataset.label)
}
this.labelTarget.innerText = labels.join(', ')
})
if (0 === labels.length) {
this.labelTarget.innerText = this.placeholderValue
}
}
clickOutside(e) {
this.dropdownTarget.classList.toggle('hidden', true)
}
}
@@ -1,11 +0,0 @@
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
static targets = [ 'field' ]
toggle() {
let type = this.fieldTarget.getAttribute('type') === 'password' ? 'text' : 'password'
this.fieldTarget.setAttribute('type', type)
}
}
@@ -1,166 +0,0 @@
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
static targets = ['mount', 'error', 'message', 'resetButton', 'day', 'dateFrom', 'dateTo', 'submit']
static values = {
hotelCode: String,
selectedFrom: String,
selectedTo: String,
calendarRefreshUrl: String,
}
connect() {
this.startDate = null
this.endDate = null
this.sessionRestored = false
// Re-apply highlights after every HTMX month swap (navigation or initial load).
this.mountTarget.addEventListener('htmx:afterSwap', () => requestAnimationFrame(() => this.initAfterLoad()))
this.mountTarget.addEventListener('htmx:responseError', () => this.showError())
}
initAfterLoad() {
// Restore from session values exactly once on the first swap.
if (!this.sessionRestored) {
this.sessionRestored = true
const from = this.selectedFromValue
const to = this.selectedToValue
if (from && to) {
this.startDate = from
this.endDate = to
if (this.hasResetButtonTarget) this.resetButtonTarget.classList.remove('hidden')
}
}
this.updateDisplay()
}
selectDate(event) {
const btn = event.currentTarget
btn.blur()
const date = btn.dataset.date
const status = btn.dataset.status
if (!status || status === 'blocked' || status === 'past') return
if (this.startDate && this.endDate) {
this.resetSelection()
}
if (!this.startDate) {
if (status === 'checkout-only') {
this.showMessage('Bitte wähle einen Anreisetag.')
return
}
this.startDate = date
this.endDate = null
this.updateDisplay()
this.showMessage('Bitte wähle das Abreisedatum.')
return
}
if (date === this.startDate) {
this.resetSelection()
return
}
const [from, to] = date < this.startDate ? [date, this.startDate] : [this.startDate, date]
if (this.hasBlockedInRange(from, to)) {
this.resetSelection()
this.showMessage('Dieser Zeitraum enthält nicht verfügbare Daten.')
return
}
const startBtn = this.dayTargets.find(b => b.dataset.date === from)
const minNights = parseInt(startBtn?.dataset.minNights) || 0
const nights = (new Date(to) - new Date(from)) / 86400000
if (minNights > 0 && nights < minNights) {
this.showMessage(`Weniger als ${minNights} Nächte nur auf Anfrage.`)
} else {
this.hideMessage()
}
this.startDate = from
this.endDate = to
this.updateDisplay()
this.activateSubmit(from, to)
this.saveAndRefreshSummary(from, to)
this.dispatch('range-select', { detail: { dateFrom: from, dateTo: to } })
}
hasBlockedInRange(from, to) {
for (const btn of this.dayTargets) {
const d = btn.dataset.date
const s = btn.dataset.status
if (d >= from && d < to && (s === 'blocked' || s === 'past' || s === 'checkout-only')) return true
}
return false
}
updateDisplay() {
for (const btn of this.dayTargets) {
const d = btn.dataset.date
btn.classList.remove('pc-day--pending-start', 'pc-day--selected-start', 'pc-day--selected-end', 'pc-day--in-range')
if (!this.startDate) continue
if (d === this.startDate) {
btn.classList.add(this.endDate ? 'pc-day--selected-start' : 'pc-day--pending-start')
} else if (this.endDate) {
if (d === this.endDate) btn.classList.add('pc-day--selected-end')
else if (d > this.startDate && d < this.endDate) btn.classList.add('pc-day--in-range')
}
}
}
activateSubmit(dateFrom, dateTo) {
if (this.hasDateFromTarget) this.dateFromTarget.value = dateFrom
if (this.hasDateToTarget) this.dateToTarget.value = dateTo
if (this.hasSubmitTarget) {
this.submitTarget.disabled = false
this.submitTarget.classList.remove('opacity-50', 'cursor-not-allowed', 'pointer-events-none')
}
if (this.hasResetButtonTarget) this.resetButtonTarget.classList.remove('hidden')
}
resetSelection() {
this.startDate = null
this.endDate = null
this.updateDisplay()
this.hideMessage()
if (this.hasDateFromTarget) this.dateFromTarget.value = ''
if (this.hasDateToTarget) this.dateToTarget.value = ''
if (this.hasSubmitTarget) {
this.submitTarget.disabled = true
this.submitTarget.classList.add('opacity-50', 'cursor-not-allowed', 'pointer-events-none')
}
if (this.hasResetButtonTarget) this.resetButtonTarget.classList.add('hidden')
this.saveAndRefreshSummary()
}
reset() {
this.resetSelection()
}
saveAndRefreshSummary(dateFrom = '', dateTo = '') {
if (!this.hasCalendarRefreshUrlValue) return
htmx.ajax('POST', this.calendarRefreshUrlValue, {
values: { date_from: dateFrom, date_to: dateTo },
swap: 'none',
target: this.element,
})
}
showMessage(text) {
if (this.hasMessageTarget) this.messageTarget.textContent = text
}
hideMessage() {
if (this.hasMessageTarget) this.messageTarget.textContent = ''
}
showError() {
if (this.hasErrorTarget) this.errorTarget.classList.remove('hidden')
}
}
@@ -1,33 +0,0 @@
import { Controller } from '@hotwired/stimulus'
/**
* Unchecks conflicting additional services as soon as one is selected, so the user sees the
* result immediately instead of waiting for the debounced htmx refresh. The server resolves
* the same conflicts again and stays the source of truth.
*/
export default class extends Controller {
static targets = [ 'input' ]
select(event) {
const input = event.target
if (!input.checked) {
return
}
const group = input.dataset.exclusionGroup
if (!group) {
return
}
const exclusive = '1' === input.dataset.exclusive
this.inputTargets
.filter(other => other !== input)
.filter(other => other.dataset.exclusionGroup === group)
.filter(other => exclusive || '1' === other.dataset.exclusive)
.forEach(other => { other.checked = false })
}
}
@@ -1,30 +0,0 @@
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
static classes = ['closed', 'iconClosed', 'iconExpanded']
static targets = ['submenu', 'button', 'icon']
static values = { expanded: Boolean }
toggleSubmenu() {
this.expandedValue = !this.expandedValue
}
expandedValueChanged(expanded) {
this.submenuTarget.classList.toggle(this.closedClass, false === expanded)
if (false === this.hasButtonTarget) {
return
}
this.buttonTarget.setAttribute('aria-expanded', expanded)
if (false === this.hasIconTarget) {
return
}
if (true === expanded) {
this.iconTarget.classList.add(...this.iconExpandedClasses)
this.iconTarget.classList.remove(...this.iconClosedClasses)
} else {
this.iconTarget.classList.add(...this.iconClosedClasses)
this.iconTarget.classList.remove(...this.iconExpandedClasses)
}
}
}
-90
View File
@@ -1,90 +0,0 @@
import { Controller } from '@hotwired/stimulus'
import Sortable from 'sortablejs'
export default class extends Controller {
static targets = [ 'list', 'item', 'handle', 'positionField', 'positionLabel', 'status' ]
static values = {
url: String,
}
connect() {
this.abortController = null
// The sortable container may be nested (e.g. a tbody) when the controller element also
// has to wrap elements that must not be dragged, like the status message.
new Sortable(this.hasListTarget ? this.listTarget : this.element, {
draggable: '[data-sortable-target="item"]',
handle: '[data-sortable-target="handle"]',
sort: true,
fallbackOnBody: true,
onEnd: e => {
this.updateOrdering()
this.persist()
}
})
}
disconnect() {
this.abortController?.abort()
}
updateOrdering() {
this.positionFieldTargets.forEach((field, index) => {
field.value = index + 1
})
this.positionLabelTargets.forEach((label, index) => {
label.innerText = index + 1
})
}
/**
* Sends the new order to the server. Only active when a url value is present, so the
* controller stays usable for plain form ordering.
*/
persist() {
if (!this.hasUrlValue || this.urlValue === '') {
return
}
// A drag while the previous request is still running makes that request obsolete.
this.abortController?.abort()
this.abortController = new AbortController()
const ids = this.itemTargets
.map(item => Number(item.dataset.sortableId))
.filter(id => Number.isInteger(id) && id > 0)
this.setStatus('speichert …')
fetch(this.urlValue, {
method: 'POST',
credentials: 'include',
signal: this.abortController.signal,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ ids }),
})
.then(response => {
if (!response.ok) {
throw new Error(`Unexpected response ${response.status}`)
}
this.setStatus('Reihenfolge gespeichert')
})
.catch(error => {
if (error.name === 'AbortError') {
return
}
console.error('Failed to persist ordering', error)
this.setStatus('Speichern fehlgeschlagen')
})
}
setStatus(message) {
this.statusTargets.forEach(status => {
status.innerText = message
})
}
}
+10 -1
View File
@@ -24,15 +24,24 @@ export default class extends Controller {
}
handleNotifications(event) {
console.log('[VOUCHER DEBUG] showNotifications event received:', event)
console.log('[VOUCHER DEBUG] event.detail:', event.detail)
// HTMX wraps the trigger value in an object with 'value' and 'elt' properties
// event.detail.value contains the actual array from the HX-Trigger header
const notifications = event.detail?.value || event.detail || []
console.log('[VOUCHER DEBUG] notifications array:', notifications)
console.log('[VOUCHER DEBUG] notifications count:', Array.isArray(notifications) ? notifications.length : 'not an array')
if (Array.isArray(notifications)) {
notifications.forEach((notification, index) => {
console.log(`[VOUCHER DEBUG] Processing notification ${index}:`, notification)
const className = this.getClassForType(notification.type)
this.showToast(notification.message, className)
})
} else {
console.error('[VOUCHER DEBUG] Notifications is not an array:', notifications)
}
}
@@ -57,4 +66,4 @@ export default class extends Controller {
return typeMap[type] || 'toastify--info'
}
}
}
+1 -5
View File
@@ -2,7 +2,7 @@ import {Controller} from '@hotwired/stimulus'
export default class extends Controller {
static classes = ['closed', 'open', 'iconOpen']
static targets = ['content', 'icon', 'container', 'trigger']
static targets = ['content', 'icon', 'container']
static values = {
open: {
type: Boolean,
@@ -43,10 +43,6 @@ export default class extends Controller {
this.iconTarget.classList.toggle(iconClass, true === open)
}
if (this.hasTriggerTarget) {
this.triggerTarget.setAttribute('aria-expanded', String(open))
}
// Toggle class on container element (or controller element) if specified
if (this.hasOpenClass) {
const container = this.hasContainerTarget ? this.containerTarget : this.element
+1 -2
View File
@@ -1,5 +1,5 @@
import { Controller } from '@hotwired/stimulus'
import tippy, { hideAll } from 'tippy.js'
import tippy from 'tippy.js'
export default class extends Controller {
static targets = ['trigger', 'template']
@@ -27,7 +27,6 @@ export default class extends Controller {
allowHTML: true,
interactive: true,
appendTo: document.body,
onShow(instance) { hideAll({ exclude: instance }) },
}
}
if (this.hasTriggerTarget) {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 130 130" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(3, 28)">
<path d="M107,0.3c-36.4,5.5 -81.6,19.1 -81.6,38.2c0,17.7 41.8,13.2 41.8,13.2c0,0 -67,22.3 -67,-7c0,-33.2 84.5,-44.4 106.8,-44.4Z" fill="#0084d4"/>
<path d="M17,73.5c36.4,-5.4 81.6,-19.1 81.6,-38.2c0,-17.7 -41.8,-13.2 -41.8,-13.2c0,0 67,-22.3 67,7c0,33.3 -84.5,44.4 -106.8,44.4Z" fill="#f8c62f"/>
<path d="M60.7,34.3l-12.8,4l12.2,0.8l-0.4,-2.4l1,-2.4Z" fill="#0084d4"/>
<path d="M75.9,35.2l-9.2,2.9l-3.5,9.7l-1.7,-11.3l4,-10.7l1.7,7.9l8.7,1.5Z" fill="#f8c62f"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 839 KiB

-95
View File
@@ -1,95 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="icon-table" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5" /></symbol>
<symbol id="icon-dots" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6.75a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5ZM12 12.75a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5ZM12 18.75a.75.75 0 1 1 0-1.5.75.75 0 0 1 0 1.5Z" /></symbol>
<symbol id="icon-feedback" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 01.865-.501 48.172 48.172 0 003.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0012 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018z" /></symbol>
<symbol id="icon-login" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" /></symbol>
<symbol id="icon-logout" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15M12 9l-3 3m0 0l3 3m-3-3h12.75" /></symbol>
<symbol id="icon-alert" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" /></symbol>
<symbol id="icon-close" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /></symbol>
<symbol id="icon-back" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9 15L3 9m0 0l6-6M3 9h12a6 6 0 010 12h-3" /></symbol>
<symbol id="icon-list" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zM3.75 12h.007v.008H3.75V12zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm-.375 5.25h.007v.008H3.75v-.008zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z" /></symbol>
<symbol id="icon-menu" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" /></symbol>
<symbol id="icon-edit" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /></symbol>
<symbol id="icon-plus" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" /></symbol>
<symbol id="icon-minus" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 12h-15" /></symbol>
<symbol id="icon-search" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" /></symbol>
<symbol id="icon-user" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" /></symbol>
<symbol id="icon-users" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z" /></symbol>
<symbol id="icon-delete" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><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" /></symbol>
<symbol id="icon-check" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" /></symbol>
<symbol id="icon-upload" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor"><path d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/></symbol>
<symbol id="icon-download" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" /></symbol>
<symbol id="icon-sort" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" /></symbol>
<symbol id="icon-arrow-left" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 12h-15m0 0l6.75 6.75M4.5 12l6.75-6.75" /></symbol>
<symbol id="icon-chevron-down" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" /></symbol>
<symbol id="icon-arrow-right" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12h15m0 0l-6.75-6.75M19.5 12l-6.75 6.75" /></symbol>
<symbol id="icon-document" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" /></symbol>
<symbol id="icon-filter" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 3c2.755 0 5.455.232 8.083.678.533.09.917.556.917 1.096v1.044a2.25 2.25 0 01-.659 1.591l-5.432 5.432a2.25 2.25 0 00-.659 1.591v2.927a2.25 2.25 0 01-1.244 2.013L9.75 21v-6.568a2.25 2.25 0 00-.659-1.591L3.659 7.409A2.25 2.25 0 013 5.818V4.774c0-.54.384-1.006.917-1.096A48.32 48.32 0 0112 3z" /></symbol>
<symbol id="icon-refresh" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" /></symbol>
<symbol id="icon-settings" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /></symbol>
<symbol id="icon-at" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" d="M16.5 12a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0zm0 0c0 1.657 1.007 3 2.25 3S21 13.657 21 12a9 9 0 10-2.636 6.364M16.5 12V8.25" /></symbol>
<symbol id="icon-mail" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" /></symbol>
<symbol id="icon-house" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 21v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21m0 0h4.5V3.545M12.75 21h7.5V10.75M2.25 21h1.5m18 0h-18M2.25 9l4.5-1.636M18.75 3l-1.5.545m0 6.205l3 1m1.5.5l-1.5-.5M6.75 7.364V3h-3v18m3-13.636l10.5-3.819" /></symbol>
<symbol id="icon-phone" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M2.25 6.75c0 8.284 6.716 15 15 15h2.25a2.25 2.25 0 002.25-2.25v-1.372c0-.516-.351-.966-.852-1.091l-4.423-1.106c-.44-.11-.902.055-1.173.417l-.97 1.293c-.282.376-.769.542-1.21.38a12.035 12.035 0 01-7.143-7.143c-.162-.441.004-.928.38-1.21l1.293-.97c.363-.271.527-.734.417-1.173L6.963 3.102a1.125 1.125 0 00-1.091-.852H4.5A2.25 2.25 0 002.25 4.5v2.25z" /></symbol>
<symbol id="icon-mobile" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M10.5 1.5H8.25A2.25 2.25 0 0 0 6 3.75v16.5a2.25 2.25 0 0 0 2.25 2.25h7.5A2.25 2.25 0 0 0 18 20.25V3.75a2.25 2.25 0 0 0-2.25-2.25H13.5m-3 0V3h3V1.5m-3 0h3m-3 18.75h3" /></symbol>
<symbol id="icon-calendar" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5m-9-6h.008v.008H12v-.008zM12 15h.008v.008H12V15zm0 2.25h.008v.008H12v-.008zM9.75 15h.008v.008H9.75V15zm0 2.25h.008v.008H9.75v-.008zM7.5 15h.008v.008H7.5V15zm0 2.25h.008v.008H7.5v-.008zm6.75-4.5h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V15zm0 2.25h.008v.008h-.008v-.008zm2.25-4.5h.008v.008H16.5v-.008zm0 2.25h.008v.008H16.5V15z" /></symbol>
<symbol id="icon-hand" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" d="M10.05 4.575a1.575 1.575 0 10-3.15 0v3m3.15-3v-1.5a1.575 1.575 0 013.15 0v1.5m-3.15 0l.075 5.925m3.075.75V4.575m0 0a1.575 1.575 0 013.15 0V15M6.9 7.575a1.575 1.575 0 10-3.15 0v8.175a6.75 6.75 0 006.75 6.75h2.018a5.25 5.25 0 003.712-1.538l1.732-1.732a5.25 5.25 0 001.538-3.712l.003-2.024a.668.668 0 01.198-.471 1.575 1.575 0 10-2.228-2.228 3.818 3.818 0 00-1.12 2.687M6.9 7.575V12m6.27 4.318A4.49 4.49 0 0116.35 15m.002 0h-.002" /></symbol>
<symbol id="icon-copy" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6" /></symbol>
<symbol id="icon-photo" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z" /></symbol>
<symbol id="icon-print" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path d="M6.72 13.829c-.24.03-.48.062-.72.096m.72-.096a42.415 42.415 0 0110.56 0m-10.56 0L6.34 18m10.94-4.171c.24.03.48.062.72.096m-.72-.096L17.66 18m0 0l.229 2.523a1.125 1.125 0 01-1.12 1.227H7.231c-.662 0-1.18-.568-1.12-1.227L6.34 18m11.318 0h1.091A2.25 2.25 0 0021 15.75V9.456c0-1.081-.768-2.015-1.837-2.175a48.055 48.055 0 00-1.913-.247M6.34 18H5.25A2.25 2.25 0 013 15.75V9.456c0-1.081.768-2.015 1.837-2.175a48.041 48.041 0 011.913-.247m10.5 0a48.536 48.536 0 00-10.5 0m10.5 0V3.375c0-.621-.504-1.125-1.125-1.125h-8.25c-.621 0-1.125.504-1.125 1.125v3.659M18 10.5h.008v.008H18V10.5zm-3 0h.008v.008H15V10.5z" stroke-linecap="round" stroke-linejoin="round"/></symbol>
<symbol id="icon-locked" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z" /></symbol>
<symbol id="icon-unlocked" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M13.5 10.5V6.75a4.5 4.5 0 119 0v3.75M3.75 21.75h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H3.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z" /></symbol>
<symbol id="icon-external-link" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M10 6V8H5V19H16V14H18V20C18 20.5523 17.5523 21 17 21H4C3.44772 21 3 20.5523 3 20V7C3 6.44772 3.44772 6 4 6H10ZM21 3V11H19L18.9999 6.413L11.2071 14.2071L9.79289 12.7929L17.5849 5H13V3H21Z"/></symbol>
<symbol id="icon-cookie" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M21.1634 10.9711C21.5132 10.8204 21.9579 11.0073 21.9811 11.3875C22.1494 14.1467 21.1794 16.9625 19.071 19.0709C15.1657 22.976 8.83405 22.9761 4.92886 19.0709C1.02367 15.1657 1.02377 8.83405 4.92885 4.9288C7.03704 2.82061 9.8525 1.85015 12.6115 2.01806C12.9916 2.04119 13.1787 2.48598 13.028 2.83576C12.4774 4.11367 12.7239 5.65275 13.7677 6.69657C14.3307 7.25963 15.038 7.58971 15.7706 7.68848C16.0483 7.72594 16.2738 7.95144 16.3113 8.2292C16.4101 8.96178 16.7402 9.66905 17.3032 10.2321C18.347 11.2759 19.8857 11.5218 21.1634 10.9711ZM19.7845 13.8397C19.8558 13.5362 19.6123 13.2603 19.3017 13.2337C18.0569 13.1271 16.8417 12.599 15.889 11.6463C15.3166 11.0739 14.8979 10.4061 14.6309 9.69455C14.5744 9.54422 14.4556 9.42534 14.3052 9.36892C13.5936 9.10186 12.9259 8.68322 12.3535 8.11078C11.4005 7.15778 10.8715 5.94208 10.7648 4.69683C10.7381 4.38618 10.4621 4.14264 10.1586 4.2141C8.76039 4.54327 7.43341 5.25267 6.34306 6.34301C3.21903 9.46721 3.21893 14.5326 6.34307 17.6567C9.46721 20.7809 14.5326 20.7808 17.6568 17.6567C18.7474 16.566 19.4557 15.2384 19.7845 13.8397ZM9.8786 14.1212C10.4644 14.707 10.4644 15.6567 9.8786 16.2425C9.29281 16.8283 8.34307 16.8283 7.75728 16.2425C7.17149 15.6567 7.17149 14.707 7.75728 14.1212C8.34306 13.5354 9.29281 13.5354 9.8786 14.1212ZM10.2321 8.11078C10.8179 8.69657 10.8179 9.64631 10.2321 10.2321C9.64636 10.8179 8.69661 10.8179 8.11083 10.2321C7.52504 9.64631 7.52504 8.69656 8.11083 8.11078C8.69661 7.52499 9.64636 7.52499 10.2321 8.11078ZM15.889 13.7676C16.4748 14.3534 16.4748 15.3032 15.889 15.889C15.3032 16.4747 14.3535 16.4747 13.7677 15.889C13.1819 15.3032 13.1819 14.3534 13.7677 13.7676C14.3535 13.1818 15.3032 13.1818 15.889 13.7676Z"/></symbol>
<symbol id="icon-mask" fill="currentColor" stroke="none" viewBox="0 0 576 512"><!--! Font Awesome Pro 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M288 64C39.52 64 0 182.1 0 273.5C0 379.5 78.8 448 176 448c27.33 0 51.21-6.516 66.11-36.79l19.93-40.5C268.3 358.6 278.1 352.4 288 352.1c9.9 .3711 19.7 6.501 25.97 18.63l19.93 40.5C348.8 441.5 372.7 448 400 448c97.2 0 176-68.51 176-174.5C576 182.1 536.5 64 288 64zM400 400c-18.12 0-19.56-2.924-23.04-9.986l-20.35-41.33c-13.87-26.86-38.85-43.53-66.82-44.57L288 304L286.2 304.1c-27.96 1.049-52.94 17.71-67.24 45.41l-19.93 40.49C195.6 397.1 194.1 400 176 400c-75.36 0-128-52.04-128-126.5C48 229.3 48 112 288 112s240 117.3 240 161.5C528 347.1 475.4 400 400 400zM160 192C124.7 192 96 220.7 96 256s28.65 64 64 64c35.35 0 64-28.65 64-64S195.3 192 160 192zM416 192c-35.35 0-64 28.65-64 64s28.65 64 64 64c35.35 0 64-28.65 64-64S451.3 192 416 192z"/></symbol>
<symbol id="icon-excel" fill="currentColor" stroke="none" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M365.3 93.38l-74.63-74.64C278.6 6.742 262.3 0 245.4 0H64C28.65 0 0 28.65 0 64l.0065 384c0 35.34 28.65 64 64 64H320c35.2 0 64-28.8 64-64V138.6C384 121.7 377.3 105.4 365.3 93.38zM336 448c0 8.836-7.164 16-16 16H64.02c-8.838 0-16-7.164-16-16L48 64.13c0-8.836 7.164-16 16-16h160L224 128c0 17.67 14.33 32 32 32h79.1V448zM229.1 233.3L192 280.9L154.9 233.3C146.8 222.8 131.8 220.9 121.3 229.1C110.8 237.2 108.9 252.3 117.1 262.8L161.6 320l-44.53 57.25c-8.156 10.47-6.25 25.56 4.188 33.69C125.7 414.3 130.8 416 135.1 416c7.156 0 14.25-3.188 18.97-9.25L192 359.1l37.06 47.65C233.8 412.8 240.9 416 248 416c5.125 0 10.31-1.656 14.72-5.062c10.44-8.125 12.34-23.22 4.188-33.69L222.4 320l44.53-57.25c8.156-10.47 6.25-25.56-4.188-33.69C252.2 220.9 237.2 222.8 229.1 233.3z"/></symbol>
<symbol id="icon-pdf" fill="currentColor" stroke="none" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M365.3 93.38l-74.63-74.64C278.6 6.742 262.3 0 245.4 0H64C28.65 0 0 28.65 0 64l.0065 384c0 35.34 28.65 64 64 64H320c35.2 0 64-28.8 64-64V138.6C384 121.7 377.3 105.4 365.3 93.38zM336 448c0 8.836-7.164 16-16 16H64.02c-8.838 0-16-7.164-16-16L48 64.13c0-8.836 7.164-16 16-16h160L224 128c0 17.67 14.33 32 32 32h79.1V448zM202 286.1c.877-2.688 1.74-5.398 2.582-8.145c1.434-5.762 7.488-31.54 7.488-52.47C212.1 207 197.1 192 178.6 192C160.1 192 145.1 207 145.1 225.5c0 .2969 .1641 28.81 13.85 62.3c-7.035 19.36-15.57 38.8-25.41 57.93c-21.49 10.11-39.24 22.23-52.8 36.07c-6.234 6.438-9.367 14.74-9.367 24.72c0 18.45 15.01 33.46 33.46 33.46c10.8 0 20.98-5.227 27.22-13.98c7.322-10.28 18.38-26.9 30.47-48.95c15.8-6.352 33.88-11.72 53.88-16c13.55 9.578 28.9 17.29 45.71 22.95c4.527 1.551 9.402 2.348 14.43 2.348c20.26 0 36.13-16.19 36.13-36.86c0-20.33-16.54-36.87-36.87-36.87h-3.705c-2.727 .125-20.51 1.141-45.37 5.367C216.9 308.9 208.6 298.3 202 286.1zM110.2 410.4c-3.273 4.688-12.03 2.777-12.03-5.312c0-1.754 .6289-3.43 1.729-4.555c9.02-9.219 19.94-17.05 31.85-23.72C122.3 393.1 114.3 404.7 110.2 410.4zM178.6 218.8c3.693 0 6.703 3.008 6.703 6.703c0 15.21-4.109 34.84-5.746 42.1C172.1 245 171.9 227.2 171.9 225.5C171.9 221.8 174.9 218.8 178.6 218.8zM162.3 348.3c6.611-13.48 13.22-28.46 19.38-44.7c6.389 10.92 14.56 21.86 24.96 31.97C192.6 338.8 177.4 342.9 162.3 348.3zM272.4 339.5h3.352c5.539 0 10.05 4.5 10.05 10.79c0 5.129-4.176 9.32-9.32 9.32c-2.029 0-4.059-.3164-5.852-.9414c-12.33-4.137-23.11-9.32-32.54-15.19C258.3 340.3 272.1 339.5 272.4 339.5z"/></symbol>
<symbol id="icon-file" fill="currentColor" stroke="none" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M365.3 93.38l-74.63-74.64C278.6 6.743 262.3 0 245.4 0L64-.0001c-35.35 0-64 28.65-64 64l.0065 384c0 35.35 28.65 64 64 64H320c35.2 0 64-28.8 64-64V138.6C384 121.7 377.3 105.4 365.3 93.38zM320 464H64.02c-8.836 0-15.1-7.163-16-15.1L48 64.13c-.0004-8.837 7.163-16 16-16h160L224 128c0 17.67 14.33 32 32 32h79.1v288C336 456.8 328.8 464 320 464z"/></symbol>
<symbol id="icon-sigma" fill="currentColor" stroke="none" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M335.1 136l.0005-56H83.59l165 158.7C253.3 243.2 255.1 249.5 255.1 256s-2.656 12.78-7.375 17.31L83.59 432h252.4l-.0005-56c0-13.25 10.75-24 24-24C373.2 352 384 362.8 384 376v80c0 13.25-10.75 24-24 24H23.99c-9.782 0-18.59-5.938-22.25-15.03s-1.438-19.47 5.625-26.28L197.4 256L7.364 73.31C.3015 66.5-1.917 56.13 1.739 47.03S14.21 32 23.99 32h336C373.2 32 384 42.75 384 56v80C384 149.3 373.2 160 359.1 160C346.7 160 335.1 149.3 335.1 136z"/></symbol>
<symbol id="icon-percent" fill="currentColor" stroke="none" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M376.1 71.03c-9.375-9.375-24.56-9.375-33.94 0l-336 336c-9.375 9.375-9.375 24.56 0 33.94C11.72 445.7 17.84 448 24 448s12.28-2.344 16.97-7.031l336-336C386.3 95.59 386.3 80.41 376.1 71.03zM64 176c26.51 0 48-21.49 48-48S90.51 80 64 80C37.49 80 16 101.5 16 128S37.49 176 64 176zM320 336c-26.51 0-48 21.49-48 48s21.49 48 48 48c26.51 0 48-21.49 48-48S346.5 336 320 336z"/></symbol>
<symbol id="icon-chair" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M288 16c26.5 0 48 21.5 48 48V256h16V64c0-35.3-28.7-64-64-64H160C124.7 0 96 28.7 96 64V256h16V64c0-26.5 21.5-48 48-48H288zM48 168c0-4.4-3.6-8-8-8s-8 3.6-8 8v80c0 4.4 3.6 8 8 8s8-3.6 8-8V168zm368 0c0-4.4-3.6-8-8-8s-8 3.6-8 8v80c0 4.4 3.6 8 8 8s8-3.6 8-8V168zM80 304H368c6.1 0 11.6 3.4 14.3 8.8l16 32c2.5 5 2.2 10.9-.7 15.6s-8.1 7.6-13.6 7.6H224 64c-5.5 0-10.7-2.9-13.6-7.6s-3.2-10.6-.7-15.6l16-32c2.7-5.4 8.3-8.8 14.3-8.8zm152 80H384c11.1 0 21.4-5.7 27.2-15.2s6.4-21.2 1.4-31.1l-16-32C391.2 294.8 380.1 288 368 288H80c-12.1 0-23.2 6.8-28.6 17.7l-16 32c-5 9.9-4.4 21.7 1.4 31.1S52.9 384 64 384H216v64H184c-30.9 0-56 25.1-56 56c0 4.4 3.6 8 8 8s8-3.6 8-8c0-22.1 17.9-40 40-40h32v40c0 4.4 3.6 8 8 8s8-3.6 8-8V464h32c22.1 0 40 17.9 40 40c0 4.4 3.6 8 8 8s8-3.6 8-8c0-30.9-25.1-56-56-56H232V384z"/></symbol>
<symbol id="icon-eye" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /></symbol>
<symbol id="icon-profile" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" d="M7.864 4.243A7.5 7.5 0 0119.5 10.5c0 2.92-.556 5.709-1.568 8.268M5.742 6.364A7.465 7.465 0 004.5 10.5a7.464 7.464 0 01-1.15 3.993m1.989 3.559A11.209 11.209 0 008.25 10.5a3.75 3.75 0 117.5 0c0 .527-.021 1.049-.064 1.565M12 10.5a14.94 14.94 0 01-3.6 9.75m6.633-4.596a18.666 18.666 0 01-2.485 5.33" /></symbol>
<symbol id="icon-chart" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 3v11.25A2.25 2.25 0 006 16.5h2.25M3.75 3h-1.5m1.5 0h16.5m0 0h1.5m-1.5 0v11.25A2.25 2.25 0 0118 16.5h-2.25m-7.5 0h7.5m-7.5 0l-1 3m8.5-3l1 3m0 0l.5 1.5m-.5-1.5h-9.5m0 0l-.5 1.5M9 11.25v1.5M12 9v3.75m3-6v6" /></symbol>
<symbol id="icon-info" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" /></symbol>
<symbol id="icon-star" fill="currentColor" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z" /></symbol>
<symbol id="icon-cancel" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></symbol>
<symbol id="icon-bell" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" /></symbol>
<symbol id="icon-folder" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path d="M2.25 12.75V12A2.25 2.25 0 014.5 9.75h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z" stroke-linecap="round" stroke-linejoin="round"/></symbol>
<symbol id="icon-power" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M5.636 5.636a9 9 0 1 0 12.728 0M12 3v9" /></symbol>
<symbol id="icon-no-symbol" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M18.364 18.364A9 9 0 0 0 5.636 5.636m12.728 12.728A9 9 0 0 1 5.636 5.636m12.728 12.728L5.636 5.636" /></symbol>
<symbol id="icon-draggable" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M8.5 7C9.32843 7 10 6.32843 10 5.5C10 4.67157 9.32843 4 8.5 4C7.67157 4 7 4.67157 7 5.5C7 6.32843 7.67157 7 8.5 7ZM8.5 13.5C9.32843 13.5 10 12.8284 10 12C10 11.1716 9.32843 10.5 8.5 10.5C7.67157 10.5 7 11.1716 7 12C7 12.8284 7.67157 13.5 8.5 13.5ZM10 18.5C10 19.3284 9.32843 20 8.5 20C7.67157 20 7 19.3284 7 18.5C7 17.6716 7.67157 17 8.5 17C9.32843 17 10 17.6716 10 18.5ZM15.5 7C16.3284 7 17 6.32843 17 5.5C17 4.67157 16.3284 4 15.5 4C14.6716 4 14 4.67157 14 5.5C14 6.32843 14.6716 7 15.5 7ZM17 12C17 12.8284 16.3284 13.5 15.5 13.5C14.6716 13.5 14 12.8284 14 12C14 11.1716 14.6716 10.5 15.5 10.5C16.3284 10.5 17 11.1716 17 12ZM15.5 20C16.3284 20 17 19.3284 17 18.5C17 17.6716 16.3284 17 15.5 17C14.6716 17 14 17.6716 14 18.5C14 19.3284 14.6716 20 15.5 20Z"/></symbol>
<symbol id="icon-discount" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M10.0544 2.0941C11.1756 1.13856 12.8248 1.13855 13.9461 2.09411L15.2941 3.24286C15.4542 3.37935 15.6533 3.46182 15.8631 3.47856L17.6286 3.61945C19.0971 3.73663 20.2633 4.9028 20.3805 6.37131L20.5214 8.13679C20.5381 8.34654 20.6205 8.54568 20.757 8.70585L21.9058 10.0539C22.8614 11.1751 22.8614 12.8243 21.9058 13.9456L20.757 15.2935C20.6206 15.4537 20.538 15.6529 20.5213 15.8627L20.3805 17.6281C20.2633 19.0967 19.0971 20.2628 17.6286 20.3799L15.8631 20.5208C15.6533 20.5376 15.4542 20.6201 15.2941 20.7566L13.9461 21.9053C12.8248 22.8609 11.1756 22.8608 10.0543 21.9053L8.70631 20.7566C8.54615 20.6201 8.34705 20.5376 8.1373 20.5209L6.37184 20.3799C4.9033 20.2627 3.73716 19.0966 3.61997 17.6281L3.47906 15.8627C3.46232 15.6529 3.37983 15.4538 3.24336 15.2936L2.0946 13.9455C1.13905 12.8243 1.13904 11.1752 2.09458 10.0539L3.24334 8.70589C3.37983 8.54573 3.46234 8.34654 3.47907 8.13678L3.61996 6.3713C3.73714 4.90278 4.90327 3.73665 6.3718 3.61946L8.13729 3.47857C8.34705 3.46183 8.54619 3.37935 8.70636 3.24286L10.0544 2.0941ZM12.6488 3.61632C12.2751 3.29782 11.7253 3.29781 11.3516 3.61632L10.0036 4.76509C9.5231 5.17456 8.92568 5.42201 8.29637 5.47223L6.5309 5.61312C6.04139 5.65219 5.65268 6.04089 5.61362 6.53041L5.47272 8.29593C5.4225 8.92521 5.17505 9.52259 4.76559 10.0031L3.61683 11.3511C3.29832 11.7248 3.29831 12.2746 3.61683 12.6483L4.76559 13.9963C5.17506 14.4768 5.4225 15.0743 5.47275 15.7035L5.61363 17.469C5.65268 17.9585 6.04139 18.3473 6.53092 18.3863L8.29636 18.5272C8.92563 18.5774 9.5231 18.8249 10.0036 19.2344L11.3516 20.3831C11.7254 20.7016 12.2751 20.7016 12.6488 20.3831L13.9969 19.2343C14.4773 18.8249 15.0747 18.5774 15.704 18.5272L17.4695 18.3863C17.959 18.3472 18.3478 17.9585 18.3868 17.469L18.5277 15.7035C18.5779 15.0742 18.8253 14.4768 19.2349 13.9964L20.3836 12.6483C20.7022 12.2746 20.7021 11.7249 20.3836 11.3511L19.2348 10.0031C18.8253 9.52259 18.5779 8.92519 18.5277 8.2959L18.3868 6.53041C18.3478 6.0409 17.959 5.65219 17.4695 5.61312L15.704 5.47224C15.0748 5.42203 14.4773 5.17455 13.9968 4.76508L12.6488 3.61632ZM14.8284 7.75718L16.2426 9.1714L9.17154 16.2425L7.75733 14.8282L14.8284 7.75718ZM10.2322 10.232C9.64641 10.8178 8.69667 10.8178 8.11088 10.232C7.52509 9.6463 7.52509 8.69652 8.11088 8.11073C8.69667 7.52494 9.64641 7.52494 10.2322 8.11073C10.818 8.69652 10.818 9.6463 10.2322 10.232ZM13.7677 15.8889C14.3535 16.4747 15.3032 16.4747 15.889 15.8889C16.4748 15.3031 16.4748 14.3534 15.889 13.7676C15.3032 13.1818 14.3535 13.1818 13.7677 13.7676C13.1819 14.3534 13.1819 15.3031 13.7677 15.8889Z"/></symbol>
<symbol id="icon-stack" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M20.0833 15.1999L21.2854 15.9212C21.5221 16.0633 21.5989 16.3704 21.4569 16.6072C21.4146 16.6776 21.3557 16.7365 21.2854 16.7787L12.5144 22.0412C12.1977 22.2313 11.8021 22.2313 11.4854 22.0412L2.71451 16.7787C2.47772 16.6366 2.40093 16.3295 2.54301 16.0927C2.58523 16.0223 2.64413 15.9634 2.71451 15.9212L3.9166 15.1999L11.9999 20.0499L20.0833 15.1999ZM20.0833 10.4999L21.2854 11.2212C21.5221 11.3633 21.5989 11.6704 21.4569 11.9072C21.4146 11.9776 21.3557 12.0365 21.2854 12.0787L11.9999 17.6499L2.71451 12.0787C2.47772 11.9366 2.40093 11.6295 2.54301 11.3927C2.58523 11.3223 2.64413 11.2634 2.71451 11.2212L3.9166 10.4999L11.9999 15.3499L20.0833 10.4999ZM12.5144 1.30864L21.2854 6.5712C21.5221 6.71327 21.5989 7.0204 21.4569 7.25719C21.4146 7.32757 21.3557 7.38647 21.2854 7.42869L11.9999 12.9999L2.71451 7.42869C2.47772 7.28662 2.40093 6.97949 2.54301 6.7427C2.58523 6.67232 2.64413 6.61343 2.71451 6.5712L11.4854 1.30864C11.8021 1.11864 12.1977 1.11864 12.5144 1.30864ZM11.9999 3.33233L5.88723 6.99995L11.9999 10.6676L18.1126 6.99995L11.9999 3.33233Z"/></symbol>
<symbol id="icon-bus" xmlns="http://www.w3.org/2000/svg" stroke-width="1.5" viewBox="0 0 24 24" stroke="currentColor" fill="none"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M6 17m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /><path d="M18 17m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /><path d="M4 17h-2v-11a1 1 0 0 1 1 -1h14a5 7 0 0 1 5 7v5h-2m-4 0h-8" /><path d="M16 5l1.5 7l4.5 0" /><path d="M2 10l15 0" /><path d="M7 5l0 5" /><path d="M12 5l0 5" /></symbol>
<symbol id="icon-ski" fill="currentColor" stroke="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M380.7 48a48 48 0 1 1 96 0 48 48 0 1 1 -96 0zM2.7 268.9c6.1-11.8 20.6-16.3 32.4-10.2L239.8 365l49.6-74.5-82.7-87.9c-9.5-10.1-14.4-22.4-15.1-34.9l87.7 42 49.4 52.5c12.8 13.6 14.5 34.1 4.2 49.6l-50.2 75.4 135.8 70.5c13.6 7.1 29.8 7.2 43.6 .3l15.2-7.6c11.9-5.9 26.3-1.1 32.2 10.7s1.1 26.3-10.7 32.2l-15.2 7.6c-27.5 13.7-59.9 13.5-87.2-.7L12.9 301.3C1.2 295.2-3.4 280.7 2.7 268.9zM118.9 65.6L137 74.2l8.7-17.4c4-7.9 13.6-11.1 21.5-7.2s11.1 13.6 7.2 21.5l-8.5 16.9 55.5 26.6c1.7-.9 3.5-1.7 5.4-2.5l80.9-32.4c32.4-13 68.6 6.5 75.6 40.7l12.3 59.7 62.9 30.1c12 5.7 17 20 11.3 32s-20 17-32 11.3l-54.2-25.9c-1-.3-1.9-.6-2.8-1l-229.1-110-9.2 18.4c-4 7.9-13.6 11.1-21.5 7.2s-11.1-13.6-7.2-21.5l9-18-17.6-8.4c-8-3.8-11.3-13.4-7.5-21.3s13.4-11.3 21.3-7.5zm217.3 64.7c-1-4.9-6.2-7.7-10.8-5.8l-45.7 18.3 65.5 31.5-9-43.9z"/></symbol>
<symbol id="icon-snowboard" fill="currentColor" stroke="nonw" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M204.3 3c11.6-6.4 26.2-2.3 32.6 9.3l31.9 57.4c1.3 2.3 3.6 3.8 6.2 4.1l33.8 3.4c24.1 2.4 46.9 12 65.4 27.6L503.5 213.6c10.1 8.5 11.4 23.7 2.9 33.8s-23.7 11.4-33.8 2.9l-68.2-57.5-82.3 43.9 24.7 18.9c24.9 19 34.6 51.9 24.1 81.4l-28.2 79c-1.4 3.8-3.6 7-6.3 9.6l93.3 35.7c4.6 1.8 9.4 2.6 14.3 2.6H472c13.3 0 24 10.7 24 24s-10.7 24-24 24H443.8c-10.8 0-21.4-2-31.5-5.8L60.1 371.3c-11.5-4.4-22-11.2-30.8-20L7 329c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l22.4 22.4c4 4 8.7 7.1 14 9.1l19.4 7.4c-2.9-11.4 2.9-23.4 14-28.1L192 272l0-68.2c0-21.2 12-40.6 31-50.1L284.4 123l-14.1-1.4c-18.3-1.8-34.5-12.5-43.4-28.5L195 35.7c-6.4-11.6-2.3-26.2 9.3-32.6zm91.8 407.2c-.3-3.4 .1-6.9 1.3-10.3l28.2-79c3.5-9.8 .3-20.8-8-27.1L240 234.4l0 42.9c0 16.1-9.7 30.7-24.6 36.9L134 348.2l162.1 62.1zM259.6 189l20.5 15.7 84.6-45.1-17.2-14.5L259.6 189zM384 48a48 48 0 1 1 96 0 48 48 0 1 1 -96 0z"/></symbol>
<symbol id="icon-hourglass" fill="currentColor" stroke="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M24 0C10.7 0 0 10.7 0 24S10.7 48 24 48h8V67c0 40.3 16 79 44.5 107.5L158.1 256 76.5 337.5C48 366 32 404.7 32 445v19H24c-13.3 0-24 10.7-24 24s10.7 24 24 24H360c13.3 0 24-10.7 24-24s-10.7-24-24-24h-8V445c0-40.3-16-79-44.5-107.5L225.9 256l81.5-81.5C336 146 352 107.3 352 67V48h8c13.3 0 24-10.7 24-24s-10.7-24-24-24H24zM192 289.9l81.5 81.5C293 391 304 417.4 304 445v19H80V445c0-27.6 11-54 30.5-73.5L192 289.9zm0-67.9l-81.5-81.5C91 121 80 94.6 80 67V48H304V67c0 27.6-11 54-30.5 73.5L192 222.1z"/></symbol>
<symbol id="icon-car" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><circle cx="64" cy="176" r="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><circle cx="192" cy="176" r="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="88" y1="176" x2="168" y2="176" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M216,176h24a8,8,0,0,0,8-8V128a8,8,0,0,0-8-8H208L162.34,74.34A8,8,0,0,0,156.69,72H44.28a8,8,0,0,0-6.65,3.56L8,120v48a8,8,0,0,0,8,8H40" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="208" y1="120" x2="8" y2="120" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-flag-a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><g fill-rule="evenodd"><path fill="#fff" d="M640 480H0V0h640z"/><path fill="#ed2939" d="M640 480H0V320h640zm0-319.9H0V.1h640z"/></g></symbol>
<symbol id="icon-flag-ch" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><g fill-rule="evenodd" stroke-width="1pt"><path fill="#d52b1e" d="M0 0h640v480H0z"/><g fill="#fff"><path d="M170 195h300v90H170z"/><path d="M275 90h90v300h-90z"/></g></g></symbol>
<symbol id="icon-flag-d" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><path fill="#ffce00" d="M0 320h640v160H0z"/><path d="M0 0h640v160H0z"/><path fill="#d00" d="M0 160h640v160H0z"/></symbol>
<symbol id="icon-flag-f" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><g fill-rule="evenodd" stroke-width="1pt"><path fill="#fff" d="M0 0h640v480H0z"/><path fill="#00267f" d="M0 0h213.3v480H0z"/><path fill="#f31830" d="M426.7 0H640v480H426.7z"/></g></symbol>
<symbol id="icon-flag-i" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><g fill-rule="evenodd" stroke-width="1pt"><path fill="#fff" d="M0 0h640v480H0z"/><path fill="#009246" d="M0 0h213.3v480H0z"/><path fill="#ce2b37" d="M426.7 0H640v480H426.7z"/></g></symbol>
<symbol id="icon-flag-nl" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><g fill-rule="evenodd"><path fill="#21468b" d="M0 320h640v160H0z"/><path fill="#fff" d="M0 160h640v160H0z"/><path fill="#ae1c28" d="M0 0h640v160H0z"/></g></symbol>
<symbol id="icon-backpack" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><path d="M96,48h64a48,48,0,0,1,48,48V216a8,8,0,0,1-8,8H56a8,8,0,0,1-8-8V96A48,48,0,0,1,96,48Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M80,224V152a16,16,0,0,1,16-16h64a16,16,0,0,1,16,16v72" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M96,48V32a16,16,0,0,1,16-16h32a16,16,0,0,1,16,16V48" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="112" y1="88" x2="144" y2="88" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="80" y1="168" x2="176" y2="168" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="144" y1="168" x2="144" y2="184" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-barricade" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><rect x="24" y="72" width="208" height="88" rx="8" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="84" y1="72" x2="172" y2="160" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="156" y1="72" x2="232" y2="148" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="24" y1="84" x2="100" y2="160" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="192" y1="160" x2="192" y2="200" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="64" y1="160" x2="64" y2="200" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-bed" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><path d="M112,168V80H216a32,32,0,0,1,32,32v56" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="24" y1="208" x2="24" y2="48" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><polyline points="24 168 248 168 248 208" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="112" y1="80" x2="24" y2="80" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-boot" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><line x1="152" y1="120" x2="112" y2="120" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="152" y1="88" x2="112" y2="88" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M240,168v32a8,8,0,0,1-8,8H205.89a8.08,8.08,0,0,1-3.58-.84l-12.62-6.32a8.08,8.08,0,0,0-3.58-.84H169.89a8.08,8.08,0,0,0-3.58.84l-12.62,6.32a8.08,8.08,0,0,1-3.58.84H121.89a8.08,8.08,0,0,1-3.58-.84l-12.62-6.32a8.08,8.08,0,0,0-3.58-.84H85.89a8.08,8.08,0,0,0-3.58.84l-12.62,6.32a8.08,8.08,0,0,1-3.58.84H40a8,8,0,0,1-8-8V168c9.22-32.06,12-88.65,0-120H144a8,8,0,0,1,8,8v64h40A48,48,0,0,1,240,168Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="32" y1="168" x2="240" y2="168" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-lift" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><line x1="16" y1="72" x2="240" y2="32" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><rect x="40" y="104" width="176" height="112" rx="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="40" y1="168" x2="216" y2="168" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="128" y1="52" x2="128" y2="104" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="160" y1="104" x2="160" y2="168" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="96" y1="104" x2="96" y2="168" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-chat" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><path d="M71.58,144,32,176V48a8,8,0,0,1,8-8H168a8,8,0,0,1,8,8v88a8,8,0,0,1-8,8Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M80,144v40a8,8,0,0,0,8,8h96.42L224,224V96a8,8,0,0,0-8-8H176" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-weather" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><line x1="87.66" y1="56.73" x2="83.5" y2="33.09" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="56.69" y1="76.46" x2="37.03" y2="62.69" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="48.73" y1="112.31" x2="25.09" y2="116.48" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="123.52" y1="64.69" x2="137.28" y2="45.03" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M96,144a68.06,68.06,0,1,1,68,72H84a44,44,0,1,1,14.2-85.66" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M59.65,135.35a48,48,0,1,1,80.19-50.94" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-party" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><path d="M40.49,205.52,93,61.14a7.79,7.79,0,0,1,12.84-2.85l91.88,91.88A7.79,7.79,0,0,1,194.86,163L50.48,215.51A7.79,7.79,0,0,1,40.49,205.52Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M168,72s0-24,24-24,24-24,24-24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="144" y1="16" x2="144" y2="40" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="216" y1="112" x2="232" y2="128" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="216" y1="80" x2="240" y2="72" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="78.09" y1="102.09" x2="153.91" y2="177.91" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="101.11" y1="197.11" x2="58.89" y2="154.89" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-dice" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><rect width="256" height="256" fill="none"/><rect x="40" y="40" width="176" height="176" rx="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><circle cx="92" cy="84" r="12"/><circle cx="164" cy="84" r="12"/><circle cx="92" cy="128" r="12"/><circle cx="164" cy="128" r="12"/><circle cx="92" cy="172" r="12"/><circle cx="164" cy="172" r="12"/></symbol>
<symbol id="icon-flag" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><line x1="48" y1="224" x2="48" y2="56" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M48,176c64-55.43,112,55.43,176,0V56C160,111.43,112,.57,48,56" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-burger" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><path d="M48.07,96a8,8,0,0,1-7.89-9.72C46.68,55.55,83.52,32,128,32s81.32,23.55,87.82,54.28A8,8,0,0,1,207.93,96Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><polyline points="24 176 68 160 108 176 148 160 188 176 232 160" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="24" y1="128" x2="232" y2="128" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M208,168.73V184a32,32,0,0,1-32,32H80a32,32,0,0,1-32-32V167.27" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-handshake" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><polyline points="200 152 160 192 96 176 40 136" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><polyline points="72.68 70.63 128 56 183.32 70.63" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M34.37,60.42,8.85,111.48a8,8,0,0,0,3.57,10.73L40,136,72.68,70.63,45.11,56.85A8,8,0,0,0,34.37,60.42Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M216,136l27.58-13.79a8,8,0,0,0,3.57-10.73L221.63,60.42a8,8,0,0,0-10.74-3.57L183.32,70.63Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M184,72H144L98.34,116.29a8,8,0,0,0,1.38,12.42C117.23,139.9,141,139.13,160,120l40,32,16-16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><polyline points="124.06 216 82.34 205.57 56 186.75" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-badge" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><line x1="152" y1="112" x2="192" y2="112" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="152" y1="144" x2="192" y2="144" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><rect x="32" y="48" width="192" height="160" rx="8" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><circle cx="96" cy="120" r="24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M64,168c3.55-13.8,17.09-24,32-24s28.46,10.19,32,24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-parking" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><circle cx="128" cy="128" r="96" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M104,144h32a28,28,0,0,0,0-56H104v80" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-drinks" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><path d="M56,32H200L176.85,225A8,8,0,0,1,168.9,232H87.1A8,8,0,0,1,79.15,225Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="60.8" y1="72" x2="195.2" y2="72" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-sauna" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M153.599 76.8c-35.285 0-64 28.706-64 64s28.715 64 64 64 64-28.715 64-64-28.706-64-64-64Zm0 102.4c-21.205 0-38.4-17.195-38.4-38.4s17.195-38.4 38.4-38.4 38.4 17.195 38.4 38.4-17.194 38.4-38.4 38.4Zm152.824 315.623-51.2-140.8c-1.835-5.06-6.639-8.422-12.023-8.422h-89.6V230.4c0-7.074-5.726-12.8-12.8-12.8S128 223.326 128 230.4v128c0 7.074 5.726 12.8 12.8 12.8h93.44l48.137 132.378C284.263 508.775 289.178 512 294.4 512c1.451 0 2.927-.247 4.378-.776 6.638-2.415 10.077-9.754 7.645-16.401ZM209.919 396.8h-107.52c-7.074 0-12.8 5.726-12.8 12.8s5.726 12.8 12.8 12.8h107.52c7.074 0 12.8-5.726 12.8-12.8s-5.726-12.8-12.8-12.8ZM340.36 7.074c-3.157-6.323-10.863-8.875-17.169-5.726-6.323 3.166-8.892 10.846-5.726 17.178 22.886 45.79 12.228 85.726-.111 131.959-7.603 28.424-15.454 57.839-15.991 90.914-.111 7.074 5.521 12.902 12.587 13.013h.213c6.972 0 12.689-5.598 12.8-12.587.486-29.935 7.927-57.796 15.113-84.736 12.552-46.975 25.514-95.547-1.716-150.015Zm65.98 0c-3.174-6.323-10.837-8.875-17.178-5.726-6.323 3.166-8.892 10.846-5.726 17.178 22.903 45.79 12.237 85.726-.111 131.977-13.141 49.203-28.041 104.977-.324 174.251 1.997 5.009 6.81 8.047 11.887 8.047 1.587 0 3.2-.29 4.753-.913 6.562-2.628 9.762-10.078 7.134-16.64-24.559-61.389-11.426-110.575 1.271-158.148C420.599 110.123 433.578 61.551 406.34 7.074Z"/></symbol>
<symbol id="icon-shower" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M64,236a12,12,0,1,1-12-12A12,12,0,0,1,64,236Zm20-44a12,12,0,1,0,12,12A12,12,0,0,0,84,192Zm-64,0a12,12,0,1,0,12,12A12,12,0,0,0,20,192Zm32-32a12,12,0,1,0,12,12A12,12,0,0,0,52,160ZM256,40a8,8,0,0,1-8,8H219.31L191.46,75.86,169.8,202.65a16,16,0,0,1-27.09,8.66l-98-98a16,16,0,0,1,8.69-27.1L180.14,64.54l30.2-30.2A8,8,0,0,1,216,32h32A8,8,0,0,1,256,40ZM174.21,81.79,56,102l98,98Z"/></symbol>
<symbol id="icon-wifi" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><rect width="256" height="256" fill="none"/><circle cx="128" cy="204" r="12"/><path d="M232,93.19a164,164,0,0,0-208,0" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M200,129a116,116,0,0,0-144,0" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M168,165a68,68,0,0,0-80,0" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-mountain" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><circle cx="164" cy="52" r="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M8,200,81.1,75.94a8,8,0,0,1,13.8,0L168,200Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><line x1="50.35" y1="128" x2="125.65" y2="128" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path d="M146.61,163.71l33.06-55.79a8,8,0,0,1,13.76,0L248,200H168" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></symbol>
<symbol id="icon-spinner" viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg" stroke="currentColor"><!-- By Sam Herbert (@sherb), for everyone. More @ http://goo.gl/7AJzbL --><g fill="none" fill-rule="evenodd" stroke-width="2"><circle cx="22" cy="22" r="1"><animate attributeName="r" begin="0s" dur="1.8s" values="1; 20" calcMode="spline" keyTimes="0; 1" keySplines="0.165, 0.84, 0.44, 1" repeatCount="indefinite" /><animate attributeName="stroke-opacity" begin="0s" dur="1.8s" values="1; 0" calcMode="spline" keyTimes="0; 1" keySplines="0.3, 0.61, 0.355, 1" repeatCount="indefinite" /></circle><circle cx="22" cy="22" r="1"><animate attributeName="r" begin="-0.9s" dur="1.8s" values="1; 20" calcMode="spline" keyTimes="0; 1" keySplines="0.165, 0.84, 0.44, 1" repeatCount="indefinite" /><animate attributeName="stroke-opacity" begin="-0.9s" dur="1.8s" values="1; 0" calcMode="spline" keyTimes="0; 1" keySplines="0.3, 0.61, 0.355, 1" repeatCount="indefinite" /></circle></g></symbol>
</svg>

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

-1
View File
@@ -1 +0,0 @@
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 700 490" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><mask id="a"><image height="490" transform="matrix(.00288044 .00008847 .00008847 -.00288044 -.5862 .835135)" width="700" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAArwAAAHqCAAAAADD7sLoAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGsElEQVR4nO3dQW7bRgBA0SHTm/VGvWCPVQRIqy4cSVHkBKRlmvzWewsDjClybPxMZiJZnk4Dmua9BwBvJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXrD/2HsDDTt8+5j7Tp7jFytv8u90o3kE/3r//XHzqfP4wzXdH03Q+msYY8/lofDn/0TT9eDRP46WC6f4xrxxdHvzaCTe3H/PN7W9PuB3MK1/O/Wiv15tuTvjVaOfx/dR5GuOfvxZ/b/dg2UCWeMkSL1niPZiVm7Zp3WOWnflBG8eH9Tds7+kt5Sw78737upy5xYXHZX93bGZessRLlnjJsub92YrlKfsy85IlXrLES5Z4f2/nBbD19+/YsP3ayucg3v3Zq+2eMll34cMy85IlXrLES9bTrXlXLE+3HcPCU8fuoz0uMy9Z4iVLvGSJd6m918n73v6Qnm7D9iZHKGeLTd4Rvq4HmHnJEi9Z4iXrmde8B3jhy3aLziOMYWtm3t35b4y3Ei9Z4iVLvGQ984ZtjOSrtoJD3oiZlyzxkiVesp59zXuxyZuQLj917ZtMbXLh2krazLulVg2t0Q7xEiZessRLlg3b1rbZCTLMvISJlyzxkiXeBx3hZyE2u+bBF+E2bHcO8JPjOz/dV3nhmpmXLPGSJV6ynmXNu/KXTG/3+6i38Kzv92vm/TjbRvNpklxOvGSJl6xnWfOepjHGaXz/cLr8G/vfOP+aivNqcJrHuK4Nbz/38nd9/vHo+rnp/jHXS033J9xe4XqZMcZ8c/TQ+F45GsvGN43xdfk3eA/PEu9Ls2O85MqnYNlAlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVesv4HAfsUn4ytnvgAAAAASUVORK5CYII="/></mask><linearGradient id="b" gradientTransform="matrix(346.842 10.6534 -10.6534 346.842 194.415 296.129)" gradientUnits="userSpaceOnUse" x1="0" x2="1" y1="0" y2="0"><stop offset="0" stop-color="#bcbbba"/><stop offset="1" stop-color="#565553"/></linearGradient><linearGradient id="c"><stop offset="0" stop-color="#38a548"/><stop offset=".04" stop-color="#38a548"/><stop offset=".91" stop-color="#a3c639"/><stop offset="1" stop-color="#a3c639"/></linearGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="27.6449" x2="329.4659" xlink:href="#c" y1="294.368" y2="294.368"/><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="446.802" x2="605.544" xlink:href="#c" y1="267.649" y2="267.649"/><linearGradient id="f" gradientTransform="matrix(170.152 5.22629 -5.22629 170.152 451.782 264.535)" gradientUnits="userSpaceOnUse" x1="0" x2="1" y1="0" y2="0"><stop offset="0" stop-color="#118ece"/><stop offset=".04" stop-color="#118ece"/><stop offset=".91" stop-color="#184050"/><stop offset="1" stop-color="#184050"/></linearGradient><g mask="url(#a)"><path d="m194.119 305.842c82.487-5.378 144.251 2.12 145.365 2.304 103.692 17.276 164.073 19.425 201.218 16.582l.165-5.09c-26.441 1.313-62.179-2.767-105.949-8.079-34.114-4.14-128.221-34.151-239.888-35.469z" fill="url(#b)" fill-rule="nonzero"/></g><g fill-rule="nonzero"><path d="m197.896 191.813 65.607-48.765 16.602 4.882 27.895-31.182 35.653 48.047 25.115 9.5 64.998 70.249-69.739-55.007-15.345 5.156-37.617-47.693-17.036 17.035-25.195-4.806-30.27 32.225.755-19.807z" fill="#194050"/><path d="m38.408 306.474c-6.228 20.417-10.765 29.685-10.765 29.685 114.575-92.78 253.335-76.5 301.822-68.124-20.416-6.28-53.109-14.042-93.153-15.321-2.838-.095-5.695-.137-8.575-.137-63.667 0-137.636 22.097-189.329 53.897z" fill="url(#d)"/><path d="m602.405 251.387c-3.773 14.368-15.048 26.054-33.505 34.746-23.254 10.95-65.423 7.092-122.097-11.058 56.626 21.98 99.929 28.75 123.31 19.387 17.943-7.186 29.194-17.413 33.425-30.402 3.003-9.222 2.252-18.934.255-27.32.269 4.797-.095 9.741-1.388 14.647z" fill="url(#e)"/><path d="m605.397 211.094-6.403 4.315c.18.265 18.079 27.414 10.685 52.708-4.169 14.255-15.827 25.648-34.642 33.868-24.444 10.667-68.738 5.138-128.108-16.001-45.857-16.337-84.494-36.357-84.815-36.527-Line truncated

Before

Width:  |  Height:  |  Size: 8.4 KiB

-1
View File
@@ -1 +0,0 @@
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 700 490" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><mask id="a"><image height="490" transform="matrix(.00288044 .00008847 .00008847 -.00288044 -.5862 .835135)" width="700" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAArwAAAHqCAAAAADD7sLoAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGsElEQVR4nO3dQW7bRgBA0SHTm/VGvWCPVQRIqy4cSVHkBKRlmvzWewsDjClybPxMZiJZnk4Dmua9BwBvJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXLPGSJV6yxEuWeMkSL1niJUu8ZImXrD/2HsDDTt8+5j7Tp7jFytv8u90o3kE/3r//XHzqfP4wzXdH03Q+msYY8/lofDn/0TT9eDRP46WC6f4xrxxdHvzaCTe3H/PN7W9PuB3MK1/O/Wiv15tuTvjVaOfx/dR5GuOfvxZ/b/dg2UCWeMkSL1niPZiVm7Zp3WOWnflBG8eH9Tds7+kt5Sw78737upy5xYXHZX93bGZessRLlnjJsub92YrlKfsy85IlXrLES5Z4f2/nBbD19+/YsP3ayucg3v3Zq+2eMll34cMy85IlXrLES9bTrXlXLE+3HcPCU8fuoz0uMy9Z4iVLvGSJd6m918n73v6Qnm7D9iZHKGeLTd4Rvq4HmHnJEi9Z4iXrmde8B3jhy3aLziOMYWtm3t35b4y3Ei9Z4iVLvGQ984ZtjOSrtoJD3oiZlyzxkiVesp59zXuxyZuQLj917ZtMbXLh2krazLulVg2t0Q7xEiZessRLlg3b1rbZCTLMvISJlyzxkiXeBx3hZyE2u+bBF+E2bHcO8JPjOz/dV3nhmpmXLPGSJV6ynmXNu/KXTG/3+6i38Kzv92vm/TjbRvNpklxOvGSJl6xnWfOepjHGaXz/cLr8G/vfOP+aivNqcJrHuK4Nbz/38nd9/vHo+rnp/jHXS033J9xe4XqZMcZ8c/TQ+F45GsvGN43xdfk3eA/PEu9Ls2O85MqnYNlAlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVessRLlnjJEi9Z4iVLvGSJlyzxkiVesv4HAfsUn4ytnvgAAAAASUVORK5CYII="/></mask><linearGradient id="b" gradientTransform="matrix(346.842 10.6534 -10.6534 346.842 194.415 296.129)" gradientUnits="userSpaceOnUse" x1="0" x2="1" y1="0" y2="0"><stop offset="0" stop-color="#bcbbba"/><stop offset="1" stop-color="#565553"/></linearGradient><linearGradient id="c"><stop offset="0" stop-color="#38a548"/><stop offset=".04" stop-color="#38a548"/><stop offset=".91" stop-color="#a3c639"/><stop offset="1" stop-color="#a3c639"/></linearGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="27.6449" x2="329.4659" xlink:href="#c" y1="294.368" y2="294.368"/><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="446.802" x2="605.544" xlink:href="#c" y1="267.649" y2="267.649"/><linearGradient id="f" gradientTransform="matrix(170.152 5.22629 -5.22629 170.152 451.782 264.535)" gradientUnits="userSpaceOnUse" x1="0" x2="1" y1="0" y2="0"><stop offset="0" stop-color="#118ece"/><stop offset=".04" stop-color="#118ece"/><stop offset=".91" stop-color="#184050"/><stop offset="1" stop-color="#184050"/></linearGradient><g mask="url(#a)"><path d="m194.119 305.842c82.487-5.378 144.251 2.12 145.365 2.304 103.692 17.276 164.073 19.425 201.218 16.582l.165-5.09c-26.441 1.313-62.179-2.767-105.949-8.079-34.114-4.14-128.221-34.151-239.888-35.469z" fill="url(#b)" fill-rule="nonzero"/></g><g fill-rule="nonzero"><path d="m197.896 191.813 65.607-48.765 16.602 4.882 27.895-31.182 35.653 48.047 25.115 9.5 64.998 70.249-69.739-55.007-15.345 5.156-37.617-47.693-17.036 17.035-25.195-4.806-30.27 32.225.755-19.807z" fill="#194050"/><path d="m38.408 306.474c-6.228 20.417-10.765 29.685-10.765 29.685 114.575-92.78 253.335-76.5 301.822-68.124-20.416-6.28-53.109-14.042-93.153-15.321-2.838-.095-5.695-.137-8.575-.137-63.667 0-137.636 22.097-189.329 53.897z" fill="url(#d)"/><path d="m602.405 251.387c-3.773 14.368-15.048 26.054-33.505 34.746-23.254 10.95-65.423 7.092-122.097-11.058 56.626 21.98 99.929 28.75 123.31 19.387 17.943-7.186 29.194-17.413 33.425-30.402 3.003-9.222 2.252-18.934.255-27.32.269 4.797-.095 9.741-1.388 14.647z" fill="url(#e)"/><path d="m605.397 211.094-6.403 4.315c.18.265 18.079 27.414 10.685 52.708-4.169 14.255-15.827 25.648-34.642 33.868-24.444 10.667-68.738 5.138-128.108-16.001-45.857-16.337-84.494-36.357-84.815-36.527-Line truncated

Before

Width:  |  Height:  |  Size: 9.2 KiB

File diff suppressed because it is too large. Load diff
+7 -45
View File
@@ -5,8 +5,6 @@ const DEBOUNCE_MS = 200
let debounceTimeout = null
let historyRestoreGracePeriod = false
let savedScrollPosition = null
let activeRequests = 0
function getIndicator() {
return document.getElementById(INDICATOR_ID)
@@ -30,20 +28,12 @@ function hide() {
}
}
function handleBeforeRequest(event) {
function handleBeforeRequest() {
// Ignore requests triggered during history restore grace period
if (true === historyRestoreGracePeriod) {
return
}
activeRequests++
// Save scroll position of the target container before HTMX request
const target = event.detail?.target || document.getElementById('main-content')
if (target && typeof target.scrollTop === 'number') {
savedScrollPosition = { element: target, top: target.scrollTop }
}
// Don't start a new debounce if already pending
if (debounceTimeout) {
return
@@ -55,29 +45,7 @@ function handleBeforeRequest(event) {
}, DEBOUNCE_MS)
}
function handleRequestEnd() {
// Counter may already be 0 if a force-reset (history save, page show) fired
// before this afterRequest — ignore the stale completion in that case
if (0 === activeRequests) {
return
}
activeRequests--
if (0 === activeRequests) {
hide()
}
}
function handleAfterSwap() {
// Restore scroll position after HTMX swaps content
if (savedScrollPosition !== null && savedScrollPosition.element) {
savedScrollPosition.element.scrollTop = savedScrollPosition.top
savedScrollPosition = null
}
}
function handleHistoryRestore() {
activeRequests = 0
hide()
// Set grace period to ignore change events triggered by history restore
@@ -88,29 +56,23 @@ function handleHistoryRestore() {
}
function handleTimeout() {
// Don't decrement here — htmx:afterRequest always fires alongside htmx:timeout
// and handles the counter. This handler only shows the alert.
hide()
alert('Die Anfrage hat zu lange gedauert. Bitte versuchen Sie es erneut. Falls das Problem weiterhin besteht, kontaktieren Sie bitte unseren Support.')
}
function handleBeforeHistorySave() {
// Hide indicator before HTMX saves the page to history cache
activeRequests = 0
hide()
}
function handlePageShow() {
activeRequests = 0
hide()
}
// Initialize event listeners
document.body.addEventListener('htmx:beforeRequest', handleBeforeRequest)
document.body.addEventListener('htmx:afterRequest', handleRequestEnd)
document.body.addEventListener('htmx:afterSwap', handleAfterSwap)
document.body.addEventListener('htmx:afterRequest', hide)
document.body.addEventListener('htmx:timeout', handleTimeout)
document.body.addEventListener('htmx:historyRestore', handleHistoryRestore)
document.body.addEventListener('htmx:sendError', hide)
document.body.addEventListener('htmx:responseError', hide)
document.body.addEventListener('htmx:beforeHistorySave', handleBeforeHistorySave)
window.addEventListener('pageshow', handlePageShow)
window.addEventListener('popstate', handleHistoryRestore)
window.addEventListener('pageshow', hide)
window.addEventListener('popstate', handleHistoryRestore)
-29
View File
@@ -1,29 +0,0 @@
export const useFetch = controller => {
Object.assign(controller, {
checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response
} else {
const error = new Error(response.statusText)
error.response = response
throw error
}
},
parseJSON(response) {
return response.json()
},
parseHTML(response) {
return response.text()
},
getInitObject(method = 'get', body = null) {
return {
method,
body,
credentials: 'include',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
}
}
})
}
-4
View File
@@ -53,10 +53,6 @@
background-image: url('../images/bg_5.jpg'), linear-gradient(190deg, rgba(24, 82, 123, 1) 0%, rgba(22, 88, 131, 1) 62%, rgba(0, 112, 224, 1) 100%);;
}
.bg-outer--summer {
background-image: url('../images/bg_summer.jpg'), linear-gradient(190deg, rgba(24, 82, 123, 1) 0%, rgba(22, 88, 131, 1) 62%, rgba(0, 112, 224, 1) 100%);;
}
.sbw .bg-outer--2 {
background-image: url('../images/bg_7.jpg'), linear-gradient(190deg, rgba(24, 82, 123, 1) 0%, rgba(22, 88, 131, 1) 62%, rgba(0, 112, 224, 1) 100%);;
}
+5 -8
View File
@@ -1,9 +1,6 @@
@import "components/button.css";
@import "components/forms.css";
@import "components/gallery.css";
@import "components/pagination.css";
@import "components/price_calendar.css";
@import "components/toast.css";
@import "components/tooltip.css";
@import "components/typography.css";
@import "components/rte-content.css";
@import "components/forms.css";
@import "components/button.css";
@import "components/tooltip.css";
@import "components/toast.css";
@import "components/pagination.css";
-10
View File
@@ -1,10 +0,0 @@
@import "components/autocomplete.css";
@import "components/badge.css";
@import "components/button.css";
@import "components/datatable.css";
@import "components/datepicker.css";
@import "components/forms.css";
@import "components/pagination.css";
@import "components/toast.css";
@import "components/tooltip.css";
@import "components/typography.css";
-7
View File
@@ -1,7 +0,0 @@
@layer utilities {
/* Reserve the scrollbar gutter so content does not shift width when a
scrollbar appears (e.g. when a collapsible section is opened). */
.scroll-stable {
scrollbar-gutter: stable;
}
}
-7
View File
@@ -1,7 +0,0 @@
@import "tailwindcss/base";
@import "_base.css";
@import "tailwindcss/components";
@import "_components_admin.css";
@import "tailwindcss/utilities";
+1 -2
View File
@@ -4,5 +4,4 @@
@import "tailwindcss/components";
@import "_components.css";
@import "tailwindcss/utilities";
@import "_utilities.css";
@import "tailwindcss/utilities";
-33
View File
@@ -1,33 +0,0 @@
.autocomplete {
@apply relative w-full;
}
.autocomplete[data-loading="true"]:after {
@apply block absolute top-0 right-0;
@apply absolute w-4 h-4 rounded-full right-0 mr-4;
content: "";
border: 3px solid rgba(0, 0, 0, 0.12);
border-right: 3px solid rgba(0, 0, 0, 0.48);
top: 50%;
transform: translateY(-50%);
animation: rotate 1s infinite linear;
}
.autocomplete-icon {
@apply absolute top-1/2 right-0 transform -translate-y-1/2 mr-4;
}
.autocomplete[data-loading="true"] .autocomplete-icon {
@apply hidden;
}
.autocomplete-result-list {
@apply bg-white shadow-md max-h-64 overflow-y-auto;
}
.autocomplete-result {
@apply p-2;
}
.autocomplete-result:hover,
.autocomplete-result[aria-selected="true"] {
@apply bg-gray-200;
}
-3
View File
@@ -1,3 +0,0 @@
.badge {
@apply inline-flex items-center rounded-md px-1.5 py-0.5 text-xs font-medium whitespace-nowrap;
}
+11 -21
View File
@@ -1,7 +1,7 @@
.button {
@apply inline-flex items-center justify-center space-x-2 h-8 leading-8 md:h-10 md:leading-10 px-4 md:px-8 cursor-pointer;
@apply uppercase leading-none text-center text-sm md:text-base;
@apply transition-colors outline-none focus:outline-2 focus:outline-offset-2 focus:outline-primary-dark;
@apply inline-flex items-center justify-center space-x-2 h-10 leading-10 px-4 md:px-8 cursor-pointer;
@apply uppercase leading-none text-center;
@apply transition-colors outline-none focus:outline-2 focus:outline-offset-2 focus:outline-primary-light;
@apply rounded-md;
}
@@ -20,52 +20,42 @@
}
.button--secondary {
@apply bg-none bg-primary-light text-white;
@apply hover:bg-primary-light/50;
}
.button--neutral {
@apply bg-none bg-gray-200;
@apply hover:bg-gray-200/50;
}
.button--warning {
@apply bg-none bg-red-500 text-white;
@apply hover:bg-red-500/50;
@apply bg-none bg-primary-dark text-white;
@apply hover:bg-primary-light/80;
}
.sbw {
.button--primary {
@apply bg-none bg-sbw-secondary text-white;
@apply hover:bg-none hover:bg-sbw-primary/50;
@apply hover:bg-none hover:bg-sbw-primary/80;
}
.button--secondary {
@apply bg-none bg-sbw-primary-dark text-white;
@apply hover:bg-none hover:bg-sbw-primary/50;
@apply hover:bg-none hover:bg-sbw-primary/80;
}
}
.snz {
.button--primary {
@apply bg-none bg-snz-secondary text-white;
@apply hover:bg-none hover:bg-snz-primary/50;
@apply hover:bg-none hover:bg-snz-primary/80;
}
.button--secondary {
@apply bg-none bg-snz-primary-dark text-white;
@apply hover:bg-none hover:bg-snz-primary/50;
@apply hover:bg-none hover:bg-snz-primary/80;
}
}
.ser {
.button--primary {
@apply bg-none bg-ser-secondary text-white;
@apply hover:bg-none hover:bg-ser-primary/50;
@apply hover:bg-none hover:bg-ser-primary/80;
}
.button--secondary {
@apply bg-none bg-ser-primary text-white;
@apply hover:bg-none hover:bg-ser-primary/50;
@apply hover:bg-none hover:bg-ser-primary/80;
}
}
-31
View File
@@ -1,31 +0,0 @@
.data-table-wrapper {
@apply overflow-x-auto lg:overflow-x-visible mb-8;
}
.data-table-wrapper__inner {
@apply align-middle inline-block min-w-full overflow-hidden lg:overflow-visible;
}
.data-table {
@apply min-w-full;
}
.data-table tbody {
@apply bg-white;
}
.data-table tr {
@apply border border-gray-300;
}
.data-table th {
@apply px-4 py-2 bg-gray-200 text-left leading-4 font-bold text-primary align-top;
}
.data-table td {
@apply px-4 py-2 leading-5 align-top;
}
.data-table tbody tr {
@apply hover:bg-gray-100;
}
-7
View File
@@ -1,7 +0,0 @@
@import "vanilla-calendar-pro/styles/index.css";
@import "vanilla-calendar-pro/styles/themes/light.css";
[data-vc-theme=light] .vc-date[data-vc-date-selected] .vc-date__btn,
[data-vc-theme=light] .vc-date[data-vc-date-selected] .vc-date__btn:hover {
background-color: theme('colors.secondary');
}
-1
View File
@@ -1 +0,0 @@
@import "glightbox/dist/css/glightbox.min.css";
@@ -1,41 +0,0 @@
.pc-day {
@apply relative w-full text-center py-1 px-0.5 text-sm leading-tight rounded text-white cursor-pointer;
}
.pc-day--out-of-month {
@apply pointer-events-none opacity-0;
}
.pc-day[data-status="ok"] {
@apply bg-emerald-500;
}
.pc-day[data-status="blocked-to-ok"] {
background: linear-gradient(to bottom right, theme('colors.gray.400') 50%, theme('colors.emerald.500') 50%);
}
.pc-day[data-status="checkout-only"] {
background: linear-gradient(to bottom right, theme('colors.emerald.500') 50%, theme('colors.gray.400') 50%);
}
.pc-day[data-status="past"] {
@apply bg-transparent text-gray-400 cursor-default;
}
.pc-day[data-status="blocked"] {
@apply bg-gray-400 cursor-default;
}
.pc-day[data-status=""], .pc-day:not([data-status]) {
@apply text-gray-400 cursor-default;
}
.pc-day.pc-day--pending-start,
.pc-day.pc-day--selected-start,
.pc-day.pc-day--selected-end {
@apply bg-none outline-none bg-secondary text-gray-700;
}
.pc-day.pc-day--in-range {
@apply bg-none bg-secondary text-gray-700 opacity-55;
}
-13
View File
@@ -1,13 +0,0 @@
.rte-content {
p {
@apply pb-4;
}
ul {
@apply list-disc p-4;
}
ol {
@apply list-decimal p-4;
}
}
+3 -14
View File
@@ -14,17 +14,12 @@
"doctrine/doctrine-bundle": "^2.13",
"doctrine/doctrine-migrations-bundle": "^3.3",
"doctrine/orm": "^3.3",
"fakerphp/faker": "^1.24",
"flagception/flagception-bundle": "^6.1",
"knplabs/knp-menu-bundle": "^3.7",
"knplabs/knp-paginator-bundle": "^6.10",
"league/flysystem-bundle": "^3.4",
"league/flysystem-sftp-v3": "^3.29",
"league/oauth2-server-bundle": "^1.0",
"nelexa/zip": "^4.0",
"nesbot/carbon": "^3.8",
"phpdocumentor/reflection-docblock": "^5.6",
"phpoffice/phpspreadsheet": "^5.4",
"phpstan/phpdoc-parser": "^2.0",
"spatie/crypto": "^2.1",
"symfony/apache-pack": "^1.0",
@@ -56,7 +51,6 @@
"symfony/translation": "6.4.*",
"symfony/twig-bundle": "6.4.*",
"symfony/uid": "6.4.*",
"symfony/ux-twig-component": "^2.36",
"symfony/validator": "6.4.*",
"symfony/web-link": "6.4.*",
"symfony/webpack-encore-bundle": "^2.2",
@@ -64,7 +58,6 @@
"twig/extra-bundle": "^2.12|^3.0",
"twig/html-extra": "^3.15",
"twig/intl-extra": "*",
"twig/string-extra": "^3.24",
"twig/twig": "^2.12|^3.0",
"zenstruck/schedule-bundle": "^1.8"
},
@@ -76,7 +69,7 @@
},
"sort-packages": true,
"platform": {
"php": "8.3.30"
"php": "8.2.28"
}
},
"autoload": {
@@ -99,8 +92,6 @@
"symfony/polyfill-php81": "*"
},
"scripts": {
"rector": "vendor/bin/rector process",
"rector:dry-run": "vendor/bin/rector process --dry-run",
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
@@ -125,11 +116,9 @@
"require-dev": {
"deployer/deployer": "^7.5",
"friendsofphp/php-cs-fixer": "^3.75",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-doctrine": "^2.0",
"phpstan/phpstan-symfony": "^2.0",
"phpunit/phpunit": "^9.5",
"rector/rector": "^2.4",
"spatie/ray": "^1.43",
"spatie/x-ray": "^1.2",
"symfony/browser-kit": "6.4.*",
"symfony/css-selector": "6.4.*",
"symfony/debug-bundle": "6.4.*",
Generated
+1509 -2188
View File
File diff suppressed because it is too large. Load diff
-4
View File
@@ -16,8 +16,4 @@ return [
League\FlysystemBundle\FlysystemBundle::class => ['all' => true],
League\Bundle\OAuth2ServerBundle\LeagueOAuth2ServerBundle::class => ['all' => true],
Zenstruck\ScheduleBundle\ZenstruckScheduleBundle::class => ['all' => true],
Flagception\Bundle\FlagceptionBundle\FlagceptionBundle::class => ['all' => true],
Knp\Bundle\MenuBundle\KnpMenuBundle::class => ['all' => true],
Knp\Bundle\PaginatorBundle\KnpPaginatorBundle::class => ['all' => true],
Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true],
];
+2 -4
View File
@@ -15,7 +15,5 @@ framework:
#app: cache.adapter.apcu
# Namespaced pools use the above "app" backend by default
pools:
bpn.cache:
adapter: cache.adapter.filesystem
tags: true
#pools:
#my.dedicated.cache: null
-2
View File
@@ -1,2 +0,0 @@
flagception:
features: {}
+8 -4
View File
@@ -1,17 +1,21 @@
flysystem:
storages:
xml_export.storage:
local:
adapter: 'local'
options:
directory: '%env(resolve:XML_EXPORT_PATH)%'
xml_source.storage:
sftp:
adapter: 'sftp'
options:
host: '%env(SFTP_XML_EXPORT_HOST)%'
port: '%env(int:SFTP_XML_EXPORT_PORT)%'
username: '%env(SFTP_XML_EXPORT_USER)%'
password: '%env(SFTP_XML_EXPORT_PASSWORD)%'
xml_dump.storage:
local:
adapter: 'local'
options:
directory: '%kernel.project_dir%/var/bpn'
json_export.storage:
local:
adapter: 'local'
options:
directory: '%env(resolve:JSON_EXPORT_PATH)%'
+3 -2
View File
@@ -9,8 +9,9 @@ framework:
# Remove or comment this section to explicitly disable session support.
session:
handler_id: null
cookie_secure: true
cookie_samesite: lax
cookie_secure: auto
# cookie_samesite: lax
cookie_samesite: none # this is to make login work in staging environment. to be removed when going live!
#esi: true
#fragments: true
-3
View File
@@ -1,3 +0,0 @@
knp_menu:
twig:
template: _partials/_menu.html.twig
-11
View File
@@ -1,11 +0,0 @@
knp_paginator:
default_options:
page_name: page
sort_field_name: sort
sort_direction_name: direction
distinct: true
filter_field_name: filterField
filter_value_name: filterValue
template:
pagination: '_partials/_paginator_sliding.html.twig'
sortable: '_partials/_paginator_sortable_link.html.twig'
+1 -5
View File
@@ -3,12 +3,10 @@ league_oauth2_server:
private_key: '%env(resolve:OAUTH_PRIVATE_KEY)%'
private_key_passphrase: null
encryption_key: '%env(resolve:OAUTH_ENCRYPTION_KEY)%'
require_code_challenge_for_public_clients: true
enable_client_credentials_grant: true
enable_auth_code_grant: true
enable_refresh_token_grant: true
enable_refresh_token_grant: false
enable_password_grant: false
enable_implicit_grant: false
access_token_ttl: PT10M
resource_server:
public_key: '%env(resolve:OAUTH_PUBLIC_KEY)%'
@@ -17,8 +15,6 @@ league_oauth2_server:
default: ['email']
persistence:
doctrine: null
client:
allow_plaintext_secrets: false
when@test:
league_oauth2_server:
+2 -3
View File
@@ -13,7 +13,7 @@ framework:
max_retries: 3
multiplier: 2
failed: 'doctrine://default?queue_name=failed'
sync: 'sync://'
# sync: 'sync://'
default_bus: messenger.bus.default
@@ -21,10 +21,9 @@ framework:
messenger.bus.default: []
routing:
Symfony\Component\Mailer\Messenger\SendEmailMessage: sync
Symfony\Component\Mailer\Messenger\SendEmailMessage: async
Symfony\Component\Notifier\Message\ChatMessage: async
Symfony\Component\Notifier\Message\SmsMessage: async
App\Message\MailjetNewsletterEventMessage: async
# Route your messages to the transports
# 'App\Message\YourMessage': async
+3 -17
View File
@@ -4,7 +4,6 @@ monolog:
- bpn
- core
- auth
- admin
when@dev:
monolog:
@@ -28,16 +27,11 @@ when@dev:
path: "%kernel.logs_dir%/%kernel.environment%.core.log"
level: debug
channels: ["core"]
admin:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.admin.log"
level: debug
channels: ["admin"]
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: ["!event", "!bpn", "!core", "!auth", "!admin"]
channels: ["!event", "!bpn", "!core", "!auth"]
# uncomment to get logging in your browser
# you may have to allow bigger header sizes in your Web server configuration
#firephp:
@@ -65,7 +59,7 @@ when@test:
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
when@prod: &prod_config
when@prod:
monolog:
handlers:
database:
@@ -90,19 +84,13 @@ when@prod: &prod_config
path: "%kernel.logs_dir%/%kernel.environment%.core.log"
level: info
channels: ["core"]
admin:
type: rotating_file
max_files: 7
path: "%kernel.logs_dir%/%kernel.environment%.admin.log"
level: info
channels: ["admin"]
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_http_codes: [404, 405]
buffer_size: 50 # How many messages should be saved? Prevent memory leaks
channels: ["!bpn", "!core", "!auth", "!admin"]
channels: ["!bpn", "!core", "!auth"]
nested:
type: rotating_file
path: "%kernel.logs_dir%/%kernel.environment%.framework.log"
@@ -117,5 +105,3 @@ when@prod: &prod_config
channels: [deprecation]
path: php://stderr
formatter: monolog.formatter.json
when@staging: *prod_config
+1 -24
View File
@@ -1,7 +1,6 @@
security:
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\InMemoryUser: 'plaintext'
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
@@ -9,18 +8,6 @@ security:
entity:
class: App\Entity\User
property: email
mailjet_webhook_provider:
memory:
users:
mailjet:
password: '%env(MAILJET_WEBHOOK_BASIC_PASSWORD)%'
roles: [ ROLE_MAILJET_WEBHOOK ]
role_hierarchy:
ROLE_ADMIN:
- ROLE_GROUPS_ADMIN
ROLE_GROUPS_ADMIN:
- ROLE_GROUPS_MANAGER
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
@@ -32,15 +19,7 @@ security:
pattern: ^/api
security: true
stateless: true
provider: app_user_provider
oauth2: true
mailjet_webhook:
pattern: ^/webhooks/mailjet/newsletter$
security: true
stateless: true
provider: mailjet_webhook_provider
http_basic:
realm: 'Mailjet Webhook'
main:
lazy: true
provider: app_user_provider
@@ -53,9 +32,8 @@ security:
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/webhooks/mailjet/newsletter$, roles: ROLE_MAILJET_WEBHOOK, requires_channel: https }
- { path: ^/authorize, roles: IS_AUTHENTICATED_REMEMBERED, requires_channel: https }
- { path: ^/, roles: PUBLIC_ACCESS, requires_channel: https }
- { path: '^/', roles: PUBLIC_ACCESS, requires_channel: https }
when@test:
security:
@@ -64,7 +42,6 @@ when@test:
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\InMemoryUser: 'plaintext'
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
-7
View File
@@ -1,16 +1,9 @@
twig:
file_name_pattern: '*.twig'
form_themes: ['forms.html.twig']
paths:
'%kernel.project_dir%/assets/images': images
globals:
htmx_change_trigger: 'change delay:100ms'
website_base_url: '%env(APP_WEBSITE_BASE_URL)%'
customer_service_email: '%env(APP_CUSTOMER_SERVICE_EMAIL)%'
legal_notice_url: '%env(APP_LEGAL_NOTICE_URL)%'
terms_and_conditions_url: '%env(APP_TERMS_AND_CONDITIONS_URL)%'
privacy_policy_url: '%env(APP_PRIVACY_POLICY_URL)%'
insurance_revocation_url: '%env(APP_INSURANCE_REVOCATION_URL)%'
when@test:
twig:
-5
View File
@@ -1,5 +0,0 @@
twig_component:
anonymous_template_directory: 'components/'
defaults:
# Namespace & directory for components
App\Twig\Components\: 'components/'
+10 -41
View File
@@ -9,52 +9,21 @@ zenstruck_schedule:
schedule_extensions:
email_on_failure:
enabled: true
to: [email protected]
tasks:
- task: app:cleanup:xml-dumps
frequency: "0 1 * * *"
description: "Removes outdated XML dumps of requests/responses to BPN API for debugging"
- task: app:bpn:xml-sync
frequency: "*/15 8-19 * * *"
description: "Sync BusPro XML data every 15 min. during peak hours"
- task: app:bpn:xml-sync
frequency: "0 20-23,0-7 * * *"
description: "Sync BusPro XML data hourly outside peak hours"
- task: app:cleanup:log-entries
frequency: "15 1 * * *"
description: "Removes outdated log entries with a retention period of 6 months"
- task: app:draft:cleanup
frequency: "30 1 * * *"
description: "Removes expired drafts"
- task: app:cleanup:newsletter-opt-in-requests
frequency: "45 1 * * *"
description: "Removes expired pending newsletter double opt-in requests"
- task: league:oauth2-server:clear-expired-tokens
frequency: "0 * * * *"
description: "Removes expired oauth2 tokens hourly"
- task: app:bpn:refresh-travel-snapshot --refresh-after 60
frequency: "10 8-19 * * *"
description: "Syncs travel data snapshots with BusPro XML data hourly during peak hours"
- task: app:bpn:refresh-travel-snapshot --refresh-after 180
frequency: "10 20-23,0-7 * * *"
description: "Syncs travel data snapshots with BusPro XML data every 3 hours outside peak hours"
when@staging:
zenstruck_schedule:
mailer:
subject_prefix: "[MyE&P STAGING]"
when@prod:
zenstruck_schedule:
mailer:
subject_prefix: "[MyE&P PROD]"
tasks:
- task: app:bpn:xml-sync
frequency: "*/15 8-19 * * *"
description: "Syncs BusPro XML data every 15 min. during peak hours"
- task: app:bpn:xml-sync
frequency: "0 20-23,0-7 * * *"
description: "Syncs BusPro XML data hourly outside peak hours"
description: "Removes outdated log entries with a retention period of 6 months"
+25 -233
View File
@@ -5,92 +5,28 @@
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:
travel_info_base_url: '%env(APP_TRAVEL_INFO_BASE_URL)%'
terms_and_conditions_url: '%env(APP_TERMS_AND_CONDITIONS_URL)%'
path_to_keys: '%kernel.project_dir%/config/secret'
bpn_debug: '%env(APP_BPN_DEBUG)%'
default_booking_status: '%env(DEFAULT_BOOKING_STATUS)%'
newsletter_confirmation_ttl_hours: '%env(int:APP_NEWSLETTER_CONFIRMATION_TTL_HOURS)%'
travel_snapshot_retention_buffer_days: '%env(int:APP_TRAVEL_SNAPSHOT_RETENTION_BUFFER_DAYS)%'
default_email_from: '%env(APP_DEFAULT_EMAIL_FROM)%'
default_email_to: '%env(APP_DEFAULT_EMAIL_TO)%'
accommodation_inquiry_email: '%env(ACCOMMODATION_INQUIRY_EMAIL)%'
# MailJet list ids and their labels
mailjet_lists:
10321569: 'E&P Newsletter'
10321382: 'Reisen-Alert Ahrntal'
10321383: 'Reisen-Alert Davos'
10321391: 'Reisen-Alert Familienreisen'
10321384: 'Reisen-Alert Arosa-Lenzerheide'
10321385: 'Reisen-Alert Les Deux Alpes'
10321386: 'Reisen-Alert Montafon'
10321387: 'Reisen-Alert Portes du Soleil'
10321388: 'Reisen-Alert Saalbach-Hinterglemm'
10538809: 'Reisen-Alert Scuol'
10321389: 'Reisen-Alert Stubaital'
10554990: 'Reisen-Alert Ski & Boarderweek'
# Hausleitung hotel codes and their labels, assignable to users in /admin/user.
# Mirrors the "Hausleitung {CODE}" CRM selections published by BusProNet.
hotel_codes:
SSL: 'SSL'
SST: 'SST'
MVK: 'MVK'
ASB: 'ASB'
LPJ: 'LPJ'
DKS: 'DKS'
DGS: 'DGS'
DPW: 'DPW'
DKI: 'DKI'
DWW: 'DWW'
PMV: 'PMV'
ASG: 'ASG'
ASC: 'ASC'
SBW: 'SBW'
UCH: 'UCH'
SZO: 'SZO'
PCJ: 'PCJ'
KHH: 'KHH'
SVS: 'SVS'
SHM: 'SHM'
AGR: 'AGR'
# MailJet contact metadata names for name synchronization
mailjet_contact_metadata_fields:
firstName: 'vorname'
lastName: 'nachname'
# Body dimensions ranges for BodyDimensionsType and ParticipantValidator
body_dimension_ranges:
height_min: 145
height_max: 210
weight_min: 40
weight_max: 120
shoe_size_min: 35
shoe_size_max: 50
# Season data
season_winter_from: '%env(APP_SEASON_WINTER_FROM)%'
season_summer_from: '%env(APP_SEASON_SUMMER_FROM)%'
# domain mapping for theme, gtm id and cmp url
domain_config:
ep-reisen.de:
theme: base
gtm_id: GTM-56LWRF
cmp_url: https://consent.cookiefirst.com/sites/my.ep-reisen.de-28eabc35-7085-4d8f-b450-522bd1a5247c/consent.js
ski-boarderweek.de:
theme: sbw
gtm_id: GTM-MS2C8CH
cmp_url: https://consent.cookiefirst.com/sites/my.ski-boarderweek.de-d3641c34-8183-4b8d-b56e-c052e7a9223e/consent.js
semesterende-skireisen.de:
theme: ser
gtm_id: GTM-MNKDKL9
cmp_url: https://consent.cookiefirst.com/sites/my.semesterende-skireisen.de-c9b3422d-eb62-4ce4-b8f7-91e9b509e26f/consent.js
snowzone.net:
theme: snz
gtm_id: GTM-M96CKL
cmp_url: https://consent.cookiefirst.com/sites/my.snowzone.net-8e6aea0c-7d93-42a0-a822-29fff2aa5613/consent.js
# Body dimensions choices for BodyDimensionsType
body_dimensions.height_choices:
'bis 148cm': '-148'
'149 - 157cm': '149-157'
'158 - 166cm': '158-166'
'167 - 178cm': '167-178'
'179 - 185cm': '179-185'
'186 - 194cm': '186-194'
'195cm oder mehr': '195cm+'
body_dimensions.shoe_size_min: 36
body_dimensions.shoe_size_max: 48
body_dimensions.weight_choices:
'42 - 48kg': '42-48'
'49 - 57kg': '49-57'
'58 - 66kg': '58-66'
'67 - 78kg': '67-78'
'79 - 85kg': '79-85'
'86 - 94kg': '86-94'
'95kg oder mehr': '95k+'
services:
# default configuration for services in *this* file
@@ -103,7 +39,6 @@ services:
$xmlDump: '@xml_dump.storage'
$jsonExport: '@json_export.storage'
$travelInfoBaseUrl: '%env(APP_TRAVEL_INFO_BASE_URL)%'
$termsAndConditionsUrl: '%terms_and_conditions_url%'
$logger: '@monolog.logger.core'
$environment: '%kernel.environment%'
@@ -124,7 +59,7 @@ services:
bpn_username: '%env(APP_BPN_USER)%'
bpn_password: '%env(APP_BPN_PASSWORD)%'
bpn_api_ip: '%env(APP_BPN_IP)%'
bpn_api_ports: '%env(csv:APP_BPN_PORTS)%'
bpn_api_port: '%env(APP_BPN_PORT)%'
debug: '%env(bool:APP_BPN_DEBUG)%'
connection_timeout: '%env(int:APP_BPN_CONNECTION_TIMEOUT)%'
stream_timeout: '%env(int:APP_BPN_STREAM_TIMEOUT)%'
@@ -138,73 +73,17 @@ services:
arguments:
$path: '%path_to_keys%'
App\Menu\AdminMenuBuilder:
arguments:
$factory: '@knp_menu.factory'
tags:
- name: knp_menu.menu_builder
method: createMainMenu
alias: admin_main
App\Menu\GroupsMenuBuilder:
arguments:
$factory: '@knp_menu.factory'
tags:
- name: knp_menu.menu_builder
method: createMainMenu
alias: groups_main
App\Service\BpnXmlSyncManager:
arguments:
$xmlSource: '@xml_source.storage'
$xmlExport: '@xml_export.storage'
$bpnCache: '@bpn.cache'
App\Command\BpnXmlCacheInvalidateCommand:
arguments:
$xmlExport: '@xml_export.storage'
$bpnCache: '@bpn.cache'
$cache: '@cache.app'
App\Security\Crypt:
arguments:
$path: '%path_to_keys%'
App\Service\TravelSnapshotManager:
arguments:
$retentionBufferDays: '%travel_snapshot_retention_buffer_days%'
App\Service\TravelDataProvider:
App\Service\TravelDataService:
arguments:
$logger: '@monolog.logger.core'
$preferRemote: '%env(bool:APP_TRAVEL_PREFER_REMOTE)%'
$enableFallback: '%env(bool:APP_TRAVEL_ENABLE_FALLBACK)%'
App\Service\ParticipantFormSupport:
arguments:
$bodyDimensionRanges: '%body_dimension_ranges%'
App\Service\BookingEditDataLoader:
arguments:
$bpnCache: '@bpn.cache'
App\BusProNet\XmlLoader\TravelLoader:
arguments:
$cache: '@bpn.cache'
App\BusProNet\XmlLoader\HotelLoader:
arguments:
$cache: '@bpn.cache'
App\BusProNet\XmlLoader\PickupLoader:
arguments:
$cache: '@bpn.cache'
App\BusProNet\XmlLoader\InsuranceLoader:
arguments:
$cache: '@bpn.cache'
App\Service\VoucherValidator:
App\Service\VoucherValidationService:
arguments:
$cache: '@cache.app'
$logger: '@monolog.logger.bpn'
@@ -221,115 +100,28 @@ services:
arguments:
$handlers:
# Simple handlers with no external dependencies - instantiated directly
- 'App\Form\Service\ParticipantDateOfBirthFieldHandler'
- 'App\Form\Service\ParticipantAssignedRoomFieldHandler'
- 'App\Form\Service\ParticipantRemarksRoomFieldHandler'
- 'App\Form\Service\ParticipantAdditionalServicesFieldHandler'
- 'App\Form\Service\ParticipantCoursesFieldHandler'
- 'App\Form\Service\ParticipantBoardFieldHandler'
- 'App\Form\Service\ParticipantVegFieldHandler'
- 'App\Form\Service\ParticipantRentalsFieldHandler'
- 'App\Form\Service\ParticipantSkiPassFieldHandler'
- 'App\Form\Service\ParticipantTransportationOutboundFieldHandler'
- 'App\Form\Service\ParticipantTransportationInboundFieldHandler'
- 'App\Form\Service\ParticipantPickupFieldHandler'
- 'App\Form\Service\ParticipantDropOffFieldHandler'
- 'App\Form\Service\ParticipantParkingFieldHandler'
- 'App\Form\Service\ParticipantRentalInsuranceFieldHandler'
- 'App\Form\Service\ParticipantLicensePlateFieldHandler'
# Complex handlers with dependencies - use service references
- '@App\Form\Service\ParticipantDateOfBirthFieldHandler'
- '@App\Form\Service\ParticipantTransportationDiscountReplacementFieldHandler'
- '@App\Form\Service\ParticipantBulkInsuranceFieldHandler'
- '@App\Form\Service\ParticipantInsuranceFieldHandler'
- '@App\Form\Service\ParticipantPurchaseVoucherFieldHandler'
- '@App\Form\Service\ParticipantPromoVoucherFieldHandler'
- '@App\Form\Service\ParticipantParkingFieldHandler'
# Booking Status Rules
App\BusProNet\Service\StatusRule\Selection1473StatusRule: ~
App\BusProNet\Service\StatusRule\ChaperonServiceStatusRule: ~
# Booking Status Rule Registry
App\BusProNet\Service\BookingStatusRuleRegistry:
arguments:
$rules:
- '@App\BusProNet\Service\StatusRule\Selection1473StatusRule'
- '@App\BusProNet\Service\StatusRule\ChaperonServiceStatusRule'
App\Service\CmsDataProvider:
App\Service\CmsDataService:
arguments:
$httpClient: '@typo3.client'
$apiKey: 'AbcAbc123'# dummy key, not yet implemented
App\Logger\RequestIdProcessor:
tags:
- { name: monolog.processor }
App\Service\NewsletterManager:
arguments:
$newsletterConfirmationTtlHours: '%newsletter_confirmation_ttl_hours%'
$mailjetLists: '%mailjet_lists%'
$defaultMailjetListId: '%env(default::MAILJET_DEFAULT_LIST_ID)%'
App\Controller\Api\NewsletterSubscriptionController:
arguments:
$mailjetLists: '%mailjet_lists%'
App\Controller\Webhook\MailjetNewsletterWebhookController:
arguments:
$mailjetLists: '%mailjet_lists%'
App\Form\Admin\UserType:
arguments:
$hotelCodes: '%hotel_codes%'
App\Service\DomainConfigProvider:
arguments:
$domainConfig: '%domain_config%'
App\Email\Mailer:
arguments:
$defaults:
from: '%default_email_from%'
to: '%default_email_to%'
App\Service\AccommodationBookingService:
arguments:
$accommodationEmail: '%accommodation_inquiry_email%'
App\Service\AccommodationTermsUrlProvider:
arguments:
$config:
AT: '%env(ACCOMMODATION_TERMS_AT)%'
CH: '%env(ACCOMMODATION_TERMS_CH)%'
IT: '%env(ACCOMMODATION_TERMS_IT)%'
App\Service\GroupsPriceCalculator:
arguments:
$config:
runningCostsEur: '%env(float:APP_RUNNING_COSTS_FACTOR_EUR)%'
runningCostsChf: '%env(float:APP_RUNNING_COSTS_FACTOR_CHF)%'
undersubscription30Eur: '%env(float:APP_UNDERSUBSCRIPTION_SURCHARGE_30_EUR)%'
undersubscription30Chf: '%env(float:APP_UNDERSUBSCRIPTION_SURCHARGE_30_CHF)%'
undersubscription40Eur: '%env(float:APP_UNDERSUBSCRIPTION_SURCHARGE_40_EUR)%'
undersubscription40Chf: '%env(float:APP_UNDERSUBSCRIPTION_SURCHARGE_40_CHF)%'
App\Validator\Constraints\ParticipantValidator:
arguments:
$bodyDimensionRanges: '%body_dimension_ranges%'
App\BpnConnect\AbstractApiClient:
abstract: true
arguments:
$baseUrl: '%env(default::BPN_CONNECT_BASE_URL)%'
$apiKey: '%env(default::BPN_CONNECT_API_KEY)%'
App\BpnConnect\ContingentsClient:
parent: App\BpnConnect\AbstractApiClient
App\Service\MailjetApiClient:
arguments:
$apiKey: '%env(default::MAILJET_API_KEY)%'
$apiSecret: '%env(default::MAILJET_API_SECRET)%'
$apiBaseUrl: '%env(default::MAILJET_API_BASE_URL)%'
$defaultListId: '%env(default::MAILJET_DEFAULT_LIST_ID)%'
$contactMetadataFields: '%mailjet_contact_metadata_fields%'
-19
View File
@@ -1,19 +0,0 @@
parameters:
# domain mapping for theme, gtm id and cmp url
domain_config:
myep.ddev.site:
theme: base
gtm_id: GTM-56LWRF
cmp_url: https://consent.cookiefirst.com/sites/my.ep-reisen.de-28eabc35-7085-4d8f-b450-522bd1a5247c/consent.js
myswb.ddev.site:
theme: sbw
gtm_id: GTM-MS2C8CH
cmp_url: https://consent.cookiefirst.com/sites/my.ski-boarderweek.de-d3641c34-8183-4b8d-b56e-c052e7a9223e/consent.js
myser.ddev.site:
theme: ser
gtm_id: GTM-MNKDKL9
cmp_url: https://consent.cookiefirst.com/sites/my.semesterende-skireisen.de-c9b3422d-eb62-4ce4-b8f7-91e9b509e26f/consent.js
mysnz.ddev.site:
theme: snz
gtm_id: GTM-M96CKL
cmp_url: https://consent.cookiefirst.com/sites/my.snowzone.net-8e6aea0c-7d93-42a0-a822-29fff2aa5613/consent.js
+1 -1
View File
@@ -2,7 +2,7 @@ const {defineConfig} = require("cypress");
module.exports = defineConfig({
e2e: {
baseUrl: 'https://myep.ddev.site',
baseUrl: 'https://myep-next-booking.ddev.site',
supportFile: false,
},
});
+15 -40
View File
@@ -17,6 +17,7 @@ add('shared_dirs', [
add('shared_files', [
'public/.htaccess',
'.env.local.php',
]);
set('keep_releases', 3);
@@ -32,7 +33,6 @@ $rsyncOptions = [
'.ddev',
'.git',
'.github',
'.jj',
'node_modules',
'.editorconfig',
'.env.dev.local',
@@ -46,17 +46,14 @@ $rsyncOptions = [
'.phpunit.result.cache',
'config/secret/',
'CLAUDE.md',
'cypress*',
'deploy.php',
'docs',
'package.json',
'package-lock.json',
'*.http',
'http-client*.json',
'http-client.private.env.json',
'postcss.config.js',
'phpunit.xml.dist',
'public/.htaccess',
'ray.php',
'tailwind.config.js',
'webpack.config.js',
'bin/.phpunit',
@@ -77,51 +74,31 @@ $rsyncOptions = [
];
host('prod')
->setHostname('185.243.135.29')
->setRemoteUser('p704161')
->setHostname('92.205.212.39')
->setRemoteUser('ssh-53857-root')
->setForwardAgent(true)
->setSshMultiplexing(true)
->setDeployPath('/home/www/p704161/html/myep')
->setDeployPath('/kunden/tiefschnee.de/myep')
->set('writable_mode', 'chmod')
->set('http_user', 'p704161')
->set('bin/php', '/usr/local/bin/php')
->set('http_user', 'ssh-53857-root')
->set('bin/php', '/usr/bin/php82')
->set('rsync_src', __DIR__)
->set('rsync', $rsyncOptions)
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{current_path}}/public/ --web-url=https://my.ep-reisen.de')
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{release_or_current_path}}/public/ --web-url=https://my.ep-reisen.de')
;
host('staging')
->setHostname('185.243.135.29')
->setRemoteUser('p704161')
->setHostname('185.243.132.170')
->setRemoteUser('p546473')
->setForwardAgent(true)
->setSshMultiplexing(true)
->setDeployPath('/home/www/p704161/html/myep-staging')
->setDeployPath('/home/www/p546473/html/myep')
->set('writable_mode', 'chmod')
->set('http_user', 'p704161')
->set('bin/php', '/usr/local/bin/php')
->set('rsync_src', __DIR__)
->set('rsync', $rsyncOptions)
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{current_path}}/public/ --web-url=https://my.ep-reisen.net --web-basic-auth=myep:staging')
->add('shared_files', [
'public/.htpasswd',
])
;
host('develop')
->setHostname('185.243.135.29')
->setRemoteUser('p704161')
->setForwardAgent(true)
->setSshMultiplexing(true)
->setDeployPath('/home/www/p704161/html/myep-develop')
->set('writable_mode', 'chmod')
->set('http_user', 'p704161')
->set('bin/php', '/usr/local/bin/php')
->set('rsync_src', __DIR__)
->set('rsync', $rsyncOptions)
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{current_path}}/public/ --web-url=https://mydev.ep-reisen.net --web-basic-auth=myep:develop')
->add('shared_files', [
'public/.htpasswd',
])
->set('keep_releases', 5)
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{release_or_current_path}}/public/ --web-url=https://myep.dreipunktnull.net')
;
task('deploy', [
@@ -133,16 +110,14 @@ task('deploy', [
'rsync',
'deploy:shared',
'deploy:writable',
'deploy:cache:clear',
'database:migrate',
'cachetool:clear:opcache',
'deploy:publish',
'cachetool:clear:opcache',
'deploy:stop-workers',
]);
task('deploy:assets', function () {
runLocally('ddev exec npm ci');
runLocally('ddev exec npm run build');
runLocally('npm i && npm run build');
});
task('deploy:stop-workers', function () {
+475
View File
@@ -0,0 +1,475 @@
# Symfony 7.4 Upgrade Plan
**Project:** MyEP Next Booking
**Current Version:** Symfony 6.4.31
**Target Version:** Symfony 7.4 (LTS)
**Date:** 2026-01-05
**Status:** Ready for Upgrade
---
## Executive Summary
**Estimated Effort: LOW**
**Risk Level: LOW**
**Status: READY FOR UPGRADE**
The MyEP Next Booking application is well-positioned for a Symfony 7.4 upgrade. The codebase follows modern Symfony best practices, uses PHP 8 features extensively, and avoids most deprecated patterns. All pre-upgrade fixes have been completed.
**Key Facts:**
- Symfony 7.4 was released on November 27, 2025
- Requires PHP 8.2.0+ (current: PHP 8.2.29)
- LTS version with bug fixes until November 2028, security fixes until November 2029
- Symfony 8.0 = Symfony 7.4 minus deprecations (same features, PHP 8.4 required)
**Pre-Upgrade Status:**
- PHP version: 8.2.29 (compatible)
- OAuth2 Server Bundle: 1.1.0 (compatible)
- Stimulus Bundle: 2.32.0 (compatible)
- KnpMenuBundle: Removed (no longer in use)
- Doctrine ORM: 3.6.0 (compatible)
- All 312 tests passing
- Email validation mode: Configured (html5)
- 18 test-only deprecation warnings (cosmetic, do not affect runtime)
---
## Previous Plan Status
The previous upgrade plan (dated 2025-12-06) has been updated. All pre-upgrade tasks are now complete.
### Completed Items
| Item | Previous Status | Current Status |
|------|----------------|----------------|
| OAuth2 Server Bundle | 1.0.0 | **1.1.0 installed** |
| Stimulus Bundle | 2.31.0 | **2.32.0 installed** |
| PHP 8.2 deprecations (ParticipantDto::$touched) | Planned | **Completed** |
| Doctrine config (controller_resolver) | Planned | **Completed** |
| SecurityController null safety | Needs verification | **Completed** (uses `?->` and `??`) |
| Email validator "loose" mode deprecation | Needs fix | **Completed** (validator.yaml configured) |
| Failing test in BookingDataProcessorTest | Unrelated to upgrade | **Resolved** (test now passes) |
### Items No Longer Relevant
| Item | Reason |
|------|--------|
| KnpMenuBundle upgrade | **Bundle removed from project** |
---
## Current State Analysis
### PHP Version Compatibility
- **Current Runtime:** PHP 8.2.29
- **Composer Platform:** PHP 8.2.28
- **Symfony 7.4 Required:** PHP 8.2.0+
- **Status:** Compatible
### Installed Dependencies
#### Core Symfony Packages (6.4.x)
All 33 Symfony packages currently at 6.4.x need version constraint updates to 7.4.*
#### Third-Party Bundles - Compatible
| Package | Installed | Symfony 7.4 Compatible |
|---------|-----------|------------------------|
| `doctrine/orm` | 3.6.0 | Yes |
| `doctrine/doctrine-bundle` | 2.18.1 | Yes |
| `doctrine/doctrine-migrations-bundle` | 3.7.0 | Yes |
| `league/oauth2-server-bundle` | 1.1.0 | Yes |
| `symfony/stimulus-bundle` | 2.32.0 | Yes |
| `symfony/webpack-encore-bundle` | 2.4.0 | Yes |
| `symfony/monolog-bundle` | 3.11.0 | Yes |
| `zenstruck/schedule-bundle` | 1.9.0 | Yes |
### Code Quality Assessment
The codebase implements modern Symfony/PHP patterns:
- All controllers use PHP 8 attributes (`#[Route]`)
- Constructor property promotion used throughout
- Strict types enforced on all files
- Typed properties and return type declarations
- Entities use PHP 8 attributes for ORM mapping
- Modern security system (AbstractLoginFormAuthenticator)
- No deprecated annotation usage
---
## Pre-Upgrade Fixes - COMPLETED
### 1. Email Validator "loose" Mode Deprecation - DONE
**Issue:** The default mode for `#[Assert\Email]` is "loose", which is deprecated in Symfony 6.2+ and removed in Symfony 7.0.
**Resolution:** Framework default configured in `config/packages/validator.yaml`:
```yaml
framework:
validation:
email_validation_mode: html5
```
All Email constraints in the codebase also explicitly use `mode: 'strict'`:
- `src/Form/Model/ParticipantDto.php` - Has `mode: 'strict'`
- `src/Form/Model/RegistrationDto.php` - Has `mode: 'strict'`
- `src/BusProNet/Model/Communication.php` - Has `mode: 'strict'`
- `src/Controller/ResetPasswordController.php` - Has `mode: 'strict'`
### 2. Test Deprecation Warnings - COSMETIC ONLY
**Issue:** 18 deprecation warnings appear during test runs.
**Cause:** `ParticipantEditDtoTest` creates a standalone validator using `Validation::createValidatorBuilder()` which bypasses the framework's `validator.yaml` configuration.
**Impact:** These warnings are cosmetic and do not affect:
- Runtime behavior (all Email constraints use explicit `mode: 'strict'`)
- Symfony 7.4 compatibility (no code changes needed)
- Test results (all 312 tests pass)
**Note:** Warnings can be silenced with `SYMFONY_DEPRECATIONS_HELPER=disabled` if desired.
---
## Required Changes
### 1. Update Composer Version Constraints
**File:** `composer.json`
#### Symfony Core Packages
Update all packages from `6.4.*` to `7.4.*`:
```json
{
"require": {
"symfony/asset": "7.4.*",
"symfony/console": "7.4.*",
"symfony/doctrine-messenger": "7.4.*",
"symfony/dom-crawler": "7.4.*",
"symfony/dotenv": "7.4.*",
"symfony/expression-language": "7.4.*",
"symfony/form": "7.4.*",
"symfony/framework-bundle": "7.4.*",
"symfony/html-sanitizer": "7.4.*",
"symfony/http-client": "7.4.*",
"symfony/intl": "7.4.*",
"symfony/lock": "7.4.*",
"symfony/mailer": "7.4.*",
"symfony/mime": "7.4.*",
"symfony/notifier": "7.4.*",
"symfony/process": "7.4.*",
"symfony/property-access": "7.4.*",
"symfony/property-info": "7.4.*",
"symfony/runtime": "7.4.*",
"symfony/security-bundle": "7.4.*",
"symfony/serializer": "7.4.*",
"symfony/string": "7.4.*",
"symfony/translation": "7.4.*",
"symfony/twig-bundle": "7.4.*",
"symfony/uid": "7.4.*",
"symfony/validator": "7.4.*",
"symfony/web-link": "7.4.*",
"symfony/yaml": "7.4.*"
}
}
```
#### Development Packages
```json
{
"require-dev": {
"symfony/browser-kit": "7.4.*",
"symfony/css-selector": "7.4.*",
"symfony/debug-bundle": "7.4.*",
"symfony/stopwatch": "7.4.*",
"symfony/web-profiler-bundle": "7.4.*"
}
}
```
### 2. Update Symfony Flex Configuration
**File:** `composer.json`
```json
{
"extra": {
"symfony": {
"allow-contrib": true,
"require": "7.4.*",
"docker": true
}
}
}
```
---
## Potential Breaking Changes
### 1. Symfony Core Changes (Symfony 7.0 -> 7.4)
Symfony 7.0 removed all deprecated features from 6.4. Our codebase is fully compliant:
- **Native Return Types:** Already implemented
- **Attribute-based Configuration:** Already implemented
- **Security System:** Modern authenticator pattern in use
- **Form System:** Modern approach in use
- **No Annotation Usage:** All using PHP 8 attributes
### 2. Email Validation Mode
**Breaking Change:** The default `mode` for `Email` constraint changes from `loose` to `html5` in Symfony 7.0.
**Status:** Already handled - all constraints use explicit `mode: 'strict'` and framework default is set to `html5`.
### 3. Deprecation Cleanup
Deprecations accumulated in Symfony 7.1-7.4 will need review:
- Check Symfony Profiler after upgrade for any new deprecation warnings
- Review [UPGRADE-7.0.md](https://github.com/symfony/symfony/blob/7.0/UPGRADE-7.0.md)
- Review [UPGRADE-7.4.md](https://github.com/symfony/symfony/blob/7.4/UPGRADE-7.4.md)
---
## Upgrade Procedure
### Phase 1: Preparation (15 minutes)
1. **Create Feature Branch**
```bash
git checkout -b feature/symfony-7.4-upgrade
```
2. **Backup Current State**
```bash
git tag before-symfony-7.4-upgrade
```
### Phase 2: Dependency Updates (30 minutes - 1 hour)
1. **Update composer.json**
- Update all Symfony package constraints to `7.4.*`
- Update `extra.symfony.require` to `"7.4.*"`
2. **Run Composer Update**
```bash
ddev composer update
```
3. **Review Recipe Updates**
```bash
ddev composer recipes
```
Review any recipe updates from Symfony Flex and apply as needed.
4. **Clear All Caches**
```bash
ddev exec bin/console cache:clear
ddev exec bin/console cache:warmup
ddev exec "php -r 'opcache_reset();'"
```
### Phase 3: Testing & Validation (1-2 hours)
1. **Run PHPUnit Test Suite**
```bash
ddev exec ./vendor/bin/phpunit
```
Check for:
- Test failures
- Deprecation warnings
- Fatal errors
2. **Run PHP-CS-Fixer**
```bash
ddev php vendor/bin/php-cs-fixer fix --dry-run --diff
```
3. **Manual Testing - Critical Paths**
- [ ] User authentication (BPN API login)
- [ ] OAuth2 token generation (`/token` endpoint)
- [ ] OAuth2 authorization flow (`/authorize` endpoint)
- [ ] API endpoints (all `/api/*` routes)
- [ ] Booking creation flow (Steps 1-4)
- [ ] Participant form rendering and submission
- [ ] Dynamic field updates (HTMX)
- [ ] Real-time pricing calculations
- [ ] Insurance selection and filtering
- [ ] Transportation service selection
- [ ] Payment method selection
- [ ] Final booking submission to BPN API
- [ ] Booking edit functionality
- [ ] PDF/XML download functionality
- [ ] User registration
- [ ] Password reset
- [ ] Personal data management
4. **Check Symfony Profiler**
- Review deprecation warnings (should be minimal)
- Check performance metrics
- Verify no errors in logs
5. **Test Frontend Assets**
```bash
npm run build
```
- Verify Stimulus controllers load correctly
- Test HTMX interactions
- Verify Toastify notifications
- Check TailwindCSS compilation
### Phase 4: Bug Fixes (0-2 hours)
Address any issues discovered during testing:
1. **Review Error Logs**
```bash
ddev logs
```
2. **Fix Any Remaining Deprecations**
- Use Symfony Profiler to identify deprecations
- Update code to use modern alternatives
### Phase 5: Deployment (1 hour)
1. **Deploy to Staging**
```bash
ddev exec vendor/bin/dep deploy staging
```
2. **Staging Validation**
- Full regression testing
- Performance testing
3. **Production Deployment**
- Schedule maintenance window
- Deploy during low-traffic period
- Monitor error logs closely
---
## Rollback Plan
### Immediate Rollback
If critical issues are discovered:
1. **Git Revert**
```bash
git checkout master
git reset --hard before-symfony-7.4-upgrade
```
2. **Restore Dependencies**
```bash
ddev composer install
```
3. **Clear Caches**
```bash
ddev exec bin/console cache:clear
```
### Production Rollback
If issues occur in production:
```bash
ddev exec vendor/bin/dep rollback production
```
---
## Testing Checklist
### Unit Tests
- [ ] All PHPUnit tests pass (312 tests)
- [ ] No new deprecation warnings
- [ ] Code coverage maintained
### Integration Tests
- [ ] BusProNet API integration
- [ ] XML parsing and data processing
- [ ] Booking price calculations
- [ ] Insurance assignment logic
- [ ] Field handler system
### Functional Tests
- [ ] User authentication flow
- [ ] OAuth2 token generation
- [ ] API endpoints respond correctly
- [ ] Booking creation (all steps)
- [ ] Form validation
- [ ] HTMX partial updates
- [ ] Dynamic field state changes
- [ ] Real-time pricing updates
- [ ] Toast notifications
### Browser Testing
- [ ] Chrome (latest)
- [ ] Firefox (latest)
- [ ] Safari (latest)
- [ ] Mobile browsers
---
## Timeline Estimate
| Phase | Estimated Time | Notes |
|-------|---------------|-------|
| **Phase 1:** Preparation | 15 min | Branch creation |
| **Phase 2:** Dependency Updates | 30 min - 1 hour | composer.json updates, composer update |
| **Phase 3:** Testing & Validation | 1-2 hours | Automated + manual testing |
| **Phase 4:** Bug Fixes | 0-2 hours | Address any issues |
| **Phase 5:** Deployment | 1 hour | Staging deployment |
| **Total** | **2.5-6 hours** | Average: **3.5 hours** |
---
## Future Considerations: Symfony 8.0
Symfony 8.0 was released alongside 7.4 (November 2025) with identical features but:
- Requires PHP 8.4
- No deprecation layers (all deprecated code removed)
- Shorter support window (8 months)
**Recommendation:** Stay on Symfony 7.4 LTS for stability. Plan PHP 8.4 upgrade separately, then consider Symfony 8.x path.
---
## Success Criteria
- [ ] All PHPUnit tests pass (312 tests)
- [ ] No deprecation warnings in Symfony Profiler
- [ ] All critical user flows functional
- [ ] OAuth2 authentication working
- [ ] BPN API integration operational
- [ ] Booking creation flow complete
- [ ] Frontend assets compile and load
- [ ] Performance metrics comparable or better
- [ ] No errors in production logs after 24 hours
---
## Additional Resources
### Official Symfony Documentation
- [Upgrade Major Version Guide](https://symfony.com/doc/current/setup/upgrade_major.html)
- [UPGRADE-7.0.md](https://github.com/symfony/symfony/blob/7.0/UPGRADE-7.0.md)
- [UPGRADE-7.4.md](https://github.com/symfony/symfony/blob/7.4/UPGRADE-7.4.md)
- [Symfony 7.4 Release Notes](https://symfony.com/releases/7.4)
- [Preparing for Symfony 7.4 and 8.0](https://symfony.com/blog/preparing-for-symfony-7-4-and-symfony-8-0)
### Bundle-Specific Documentation
- [OAuth2 Server Bundle](https://github.com/thephpleague/oauth2-server-bundle)
- [Doctrine ORM 3.x Documentation](https://www.doctrine-project.org/projects/orm.html)
---
**Document Version:** 5.0
**Previous Version:** 4.0 (dated 2025-12-06)
**Last Updated:** 2026-01-05
**Status:** Ready for Symfony 7.4 Upgrade
+12 -74
View File
@@ -7,8 +7,8 @@
"Grant Type": "Authorization Code",
"Client ID": "{{oauth2_client_id}}",
"Client Secret": "{{oauth2_client_secret}}",
"Auth URL": "https://myep.ddev.site/authorize",
"Token URL": "https://myep.ddev.site/token",
"Auth URL": "https://myep-next-booking.ddev.site/authorize",
"Token URL": "https://myep-next-booking.ddev.site/token",
"Redirect URL": "https://myep-team.ddev.site/auth/check",
"Scope": "email"
},
@@ -17,8 +17,8 @@
"Grant Type": "Authorization Code",
"Client ID": "{{oauth2_client_id}}",
"Client Secret": "{{oauth2_client_secret}}",
"Auth URL": "https://myep.ddev.site/authorize",
"Token URL": "https://myep.ddev.site/token",
"Auth URL": "https://myep-next-booking.ddev.site/authorize",
"Token URL": "https://myep-next-booking.ddev.site/token",
"Redirect URL": "https://myep-team.ddev.site/auth/check",
"Scope": "email profile"
},
@@ -27,61 +27,8 @@
"Grant Type": "Client Credentials",
"Client ID": "{{oauth2_api_client_id}}",
"Client Secret": "{{oauth2_api_client_secret}}",
"Auth URL": "https://myep.ddev.site/authorize",
"Token URL": "https://myep.ddev.site/token",
"Scope": "api"
},
"oauth2_newsletter": {
"Type": "OAuth2",
"Grant Type": "Client Credentials",
"Client ID": "{{oauth2_api_client_id}}",
"Client Secret": "{{oauth2_api_client_secret}}",
"Auth URL": "https://myep.ddev.site/authorize",
"Token URL": "https://myep.ddev.site/token",
"Scope": "api"
}
}
}
},
"staging": {
"Security": {
"Auth": {
"oauth2_email": {
"Type": "OAuth2",
"Grant Type": "Authorization Code",
"Client ID": "{{oauth2_client_id}}",
"Client Secret": "{{oauth2_client_secret}}",
"Auth URL": "https://my.ep-reisen.net/authorize",
"Token URL": "https://my.ep-reisen.net/token",
"Redirect URL": "https://myep-team.ep-reisen.de/auth/check",
"Scope": "email"
},
"oauth2_profile": {
"Type": "OAuth2",
"Grant Type": "Authorization Code",
"Client ID": "{{oauth2_client_id}}",
"Client Secret": "{{oauth2_client_secret}}",
"Auth URL": "https://my.ep-reisen.net/authorize",
"Token URL": "https://my.ep-reisen.net/token",
"Redirect URL": "https://myep-team.ep-reisen.de/auth/check",
"Scope": "email profile"
},
"oauth2_api": {
"Type": "OAuth2",
"Grant Type": "Client Credentials",
"Client ID": "{{oauth2_api_client_id}}",
"Client Secret": "{{oauth2_api_client_secret}}",
"Auth URL": "https://my.ep-reisen.net/authorize",
"Token URL": "https://my.ep-reisen.net/token",
"Scope": "api"
},
"oauth2_newsletter": {
"Type": "OAuth2",
"Grant Type": "Client Credentials",
"Client ID": "{{oauth2_api_client_id}}",
"Client Secret": "{{oauth2_api_client_secret}}",
"Auth URL": "https://my.ep-reisen.net/authorize",
"Token URL": "https://my.ep-reisen.net/token",
"Auth URL": "https://myep-next-booking.ddev.site/authorize",
"Token URL": "https://myep-next-booking.ddev.site/token",
"Scope": "api"
}
}
@@ -95,8 +42,8 @@
"Grant Type": "Authorization Code",
"Client ID": "{{oauth2_client_id}}",
"Client Secret": "{{oauth2_client_secret}}",
"Auth URL": "https://my.ep-reisen.de/authorize",
"Token URL": "https://my.ep-reisen.de/token",
"Auth URL": "https://myep.ep-reisen.de/authorize",
"Token URL": "https://myep.ep-reisen.de/token",
"Redirect URL": "https://myep-team.ep-reisen.de/auth/check",
"Scope": "email"
},
@@ -105,8 +52,8 @@
"Grant Type": "Authorization Code",
"Client ID": "{{oauth2_client_id}}",
"Client Secret": "{{oauth2_client_secret}}",
"Auth URL": "https://my.ep-reisen.de/authorize",
"Token URL": "https://my.ep-reisen.de/token",
"Auth URL": "https://myep.ep-reisen.de/authorize",
"Token URL": "https://myep.ep-reisen.de/token",
"Redirect URL": "https://myep-team.ep-reisen.de/auth/check",
"Scope": "email profile"
},
@@ -115,17 +62,8 @@
"Grant Type": "Client Credentials",
"Client ID": "{{oauth2_api_client_id}}",
"Client Secret": "{{oauth2_api_client_secret}}",
"Auth URL": "https://my.ep-reisen.de/authorize",
"Token URL": "https://my.ep-reisen.de/token",
"Scope": "api"
},
"oauth2_newsletter": {
"Type": "OAuth2",
"Grant Type": "Client Credentials",
"Client ID": "{{oauth2_api_client_id}}",
"Client Secret": "{{oauth2_api_client_secret}}",
"Auth URL": "https://my.ep-reisen.de/authorize",
"Token URL": "https://my.ep-reisen.de/token",
"Auth URL": "https://myep.ep-reisen.de/authorize",
"Token URL": "https://myep.ep-reisen.de/token",
"Scope": "api"
}
}
-172
View File
@@ -1,172 +0,0 @@
###
# Mailjet API test requests for IntelliJ HTTP Client
#
# 1) Fill in variables below (or move them to http-client.private.env.json).
# 2) Set `mailjet_api_key` and `mailjet_api_secret` in your env file.
# IntelliJ HTTP Client will inject them into the Authorization header below.
#
# Required variables:
# - mailjet_base_url (example: https://api.mailjet.com/v3/REST)
# - mailjet_api_key
# - mailjet_api_secret
# - mailjet_contact_email
# - mailjet_list_id
#
# @no-cookie-jar
### Mailjet health check (authenticated)
# @no-cookie-jar
GET {{mailjet_base_url}}/apikey
Accept: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
### Find contact by email
# @no-cookie-jar
GET {{mailjet_base_url}}/contact?Email={{mailjet_contact_email}}
Accept: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
> {%
if (response.body && response.body.Data && response.body.Data.length > 0) {
client.global.set("contact_id", String(response.body.Data[0].ID));
}
%}
### Create contact (run if not found)
# @no-cookie-jar
POST {{mailjet_base_url}}/contact
Accept: application/json
Content-Type: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
{
"Email": "{{mailjet_contact_email}}"
}
> {%
if (response.body && response.body.Data && response.body.Data.length > 0) {
client.global.set("contact_id", String(response.body.Data[0].ID));
}
%}
### Get contact by ID (after find/create)
# @no-cookie-jar
GET {{mailjet_base_url}}/contact/{{contact_id}}
Accept: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
### Get contact metadata by ID (after find/create)
# @no-cookie-jar
GET {{mailjet_base_url}}/contactdata/{{contact_id}}
Accept: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
### Get newsletter list by ID
# @no-cookie-jar
GET {{mailjet_base_url}}/contactslist/{{mailjet_list_id}}
Accept: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
### List all available contact lists
# @no-cookie-jar
GET {{mailjet_base_url}}/contactslist?Limit=1000
Accept: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
### Check list recipient status (before actions)
# @no-cookie-jar
GET {{mailjet_base_url}}/listrecipient?ContactsList={{mailjet_list_id}}&Contact={{contact_id}}
Accept: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
> {%
if (response.body && response.body.Data && response.body.Data.length > 0) {
client.global.set("listrecipient_id", String(response.body.Data[0].ID));
}
%}
### Subscribe to list (addnoforce)
# @no-cookie-jar
POST {{mailjet_base_url}}/contactslist/{{mailjet_list_id}}/managecontact
Accept: application/json
Content-Type: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
{
"Action": "addnoforce",
"Email": "{{mailjet_contact_email}}"
}
### Verify list recipient after addnoforce
# @no-cookie-jar
GET {{mailjet_base_url}}/listrecipient?ContactsList={{mailjet_list_id}}&Contact={{contact_id}}
Accept: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
### Unsubscribe from list (unsub)
# @no-cookie-jar
POST {{mailjet_base_url}}/contactslist/{{mailjet_list_id}}/managecontact
Accept: application/json
Content-Type: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
{
"Action": "unsub",
"Email": "{{mailjet_contact_email}}"
}
### Verify list recipient after unsub
# @no-cookie-jar
GET {{mailjet_base_url}}/listrecipient?ContactsList={{mailjet_list_id}}&Contact={{contact_id}}
Accept: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
### Re-subscribe attempt with addnoforce (expected to keep unsubscribed state)
# @no-cookie-jar
POST {{mailjet_base_url}}/contactslist/{{mailjet_list_id}}/managecontact
Accept: application/json
Content-Type: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
{
"Action": "addnoforce",
"Email": "{{mailjet_contact_email}}"
}
### Verify list recipient after addnoforce re-subscribe attempt
# @no-cookie-jar
GET {{mailjet_base_url}}/listrecipient?ContactsList={{mailjet_list_id}}&Contact={{contact_id}}
Accept: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
### Re-subscribe with addforce (expected to re-subscribe)
# @no-cookie-jar
POST {{mailjet_base_url}}/contactslist/{{mailjet_list_id}}/managecontact
Accept: application/json
Content-Type: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
{
"Action": "addforce",
"Email": "{{mailjet_contact_email}}"
}
### Verify list recipient after addforce
# @no-cookie-jar
GET {{mailjet_base_url}}/listrecipient?ContactsList={{mailjet_list_id}}&Contact={{contact_id}}
Accept: application/json
Authorization: Basic {{mailjet_api_key}} {{mailjet_api_secret}}
-33
View File
@@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260106091117 extends AbstractMigration
{
public function getDescription(): string
{
return 'Create booking_edit_draft table for persisting user edits during booking edit flow';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE booking_edit_draft (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, booking_id INT NOT NULL, form_data JSON NOT NULL COMMENT \'(DC2Type:json)\', created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_E6548098A76ED395 (user_id), UNIQUE INDEX user_booking_unique (user_id, booking_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE booking_edit_draft ADD CONSTRAINT FK_E6548098A76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE booking_edit_draft DROP FOREIGN KEY FK_E6548098A76ED395');
$this->addSql('DROP TABLE booking_edit_draft');
}
}
-33
View File
@@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260109081315 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE booking_edit_draft ADD travel_date DATE NOT NULL COMMENT \'(DC2Type:date_immutable)\'');
$this->addSql('CREATE INDEX IDX_DRAFT_TRAVEL_DATE ON booking_edit_draft (travel_date)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP INDEX IDX_DRAFT_TRAVEL_DATE ON booking_edit_draft');
$this->addSql('ALTER TABLE booking_edit_draft DROP travel_date');
}
}
-26
View File
@@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260110105253 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add booking_number column to booking_edit_draft table';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE booking_edit_draft ADD booking_number INT DEFAULT NULL');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE booking_edit_draft DROP booking_number');
}
}
-28
View File
@@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260113140000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add date_id and hotel_id columns to booking_edit_draft table for export functionality';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE booking_edit_draft ADD date_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE booking_edit_draft ADD hotel_id INT DEFAULT NULL');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE booking_edit_draft DROP date_id');
$this->addSql('ALTER TABLE booking_edit_draft DROP hotel_id');
}
}
-29
View File
@@ -1,29 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260119174522 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add profile_complete flag to user table';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE user ADD profile_complete TINYINT(1) NOT NULL');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE user DROP profile_complete');
}
}
-26
View File
@@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260318113000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Create newsletter_opt_in_confirmation table for double opt-in confirmations';
}
public function up(Schema $schema): void
{
$this->addSql("CREATE TABLE newsletter_opt_in_confirmation (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(255) NOT NULL, token_hash VARCHAR(64) NOT NULL, expires_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', confirmed_at DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)', created_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', UNIQUE INDEX UNIQ_NEWSLETTER_OPT_IN_TOKEN_HASH (token_hash), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB");
}
public function down(Schema $schema): void
{
$this->addSql('DROP TABLE newsletter_opt_in_confirmation');
}
}
-28
View File
@@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260320071724 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add error_code column and index to log_entry table';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE log_entry ADD error_code VARCHAR(12) DEFAULT NULL');
$this->addSql('CREATE INDEX IDX_LOG_ENTRY_ERROR_CODE ON log_entry (error_code)');
}
public function down(Schema $schema): void
{
$this->addSql('DROP INDEX IDX_LOG_ENTRY_ERROR_CODE ON log_entry');
$this->addSql('ALTER TABLE log_entry DROP error_code');
}
}
-26
View File
@@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260321120000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Create travel_snapshot table for DB-primary travel persistence';
}
public function up(Schema $schema): void
{
$this->addSql('CREATE TABLE travel_snapshot (id INT AUTO_INCREMENT NOT NULL, date_id INT NOT NULL, hotel_id INT NOT NULL, date_code VARCHAR(64) DEFAULT NULL, label VARCHAR(255) DEFAULT NULL, product_id INT DEFAULT NULL, product_code VARCHAR(64) DEFAULT NULL, hotel_code VARCHAR(64) DEFAULT NULL, hotel_label VARCHAR(255) DEFAULT NULL, date_from DATE DEFAULT NULL COMMENT \'(DC2Type:date_immutable)\', date_to DATE DEFAULT NULL COMMENT \'(DC2Type:date_immutable)\', payload LONGTEXT NOT NULL, payload_hash VARCHAR(64) NOT NULL, captured_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', extended_refreshed_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', UNIQUE INDEX uniq_snapshot_date_hotel (date_id, hotel_id), INDEX idx_snapshot_date_code (date_code), INDEX idx_snapshot_product_id (product_id), INDEX idx_snapshot_date_to (date_to), INDEX idx_snapshot_extended_refreshed_at (extended_refreshed_at), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
}
public function down(Schema $schema): void
{
$this->addSql('DROP TABLE travel_snapshot');
}
}
-45
View File
@@ -1,45 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260323182524 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE booking_edit_draft CHANGE form_data form_data JSON NOT NULL');
$this->addSql('ALTER TABLE log_entry CHANGE context context JSON DEFAULT NULL, CHANGE extra extra JSON DEFAULT NULL');
$this->addSql('ALTER TABLE newsletter_opt_in_confirmation RENAME INDEX uniq_newsletter_opt_in_token_hash TO UNIQ_70505214B3BC57DA');
$this->addSql('ALTER TABLE user CHANGE roles roles JSON NOT NULL, CHANGE hotel_codes hotel_codes JSON NOT NULL');
$this->addSql('DROP INDEX IDX_75EA56E0FB7336F0 ON messenger_messages');
$this->addSql('DROP INDEX IDX_75EA56E0E3BD61CE ON messenger_messages');
$this->addSql('DROP INDEX IDX_75EA56E016BA31DB ON messenger_messages');
$this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0E3BD61CE16BA31DBBF396750 ON messenger_messages (queue_name, available_at, delivered_at, id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE newsletter_opt_in_confirmation RENAME INDEX uniq_70505214b3bc57da TO UNIQ_NEWSLETTER_OPT_IN_TOKEN_HASH');
$this->addSql('ALTER TABLE user CHANGE roles roles JSON NOT NULL COLLATE `utf8mb4_bin`, CHANGE hotel_codes hotel_codes JSON NOT NULL COLLATE `utf8mb4_bin`');
$this->addSql('DROP INDEX IDX_75EA56E0FB7336F0E3BD61CE16BA31DBBF396750 ON messenger_messages');
$this->addSql('CREATE INDEX IDX_75EA56E0FB7336F0 ON messenger_messages (queue_name)');
$this->addSql('CREATE INDEX IDX_75EA56E0E3BD61CE ON messenger_messages (available_at)');
$this->addSql('CREATE INDEX IDX_75EA56E016BA31DB ON messenger_messages (delivered_at)');
$this->addSql('ALTER TABLE log_entry CHANGE context context JSON DEFAULT NULL COLLATE `utf8mb4_bin`, CHANGE extra extra JSON DEFAULT NULL COLLATE `utf8mb4_bin`');
$this->addSql('ALTER TABLE booking_edit_draft CHANGE form_data form_data JSON NOT NULL COLLATE `utf8mb4_bin`');
}
}
-30
View File
@@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Changes travel_snapshot.payload from TEXT to LONGTEXT so large
* plain JSON snapshot payloads can be stored safely.
*/
final class Version20260324120000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Change travel_snapshot.payload from TEXT to LONGTEXT for plain JSON snapshot payloads';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE travel_snapshot CHANGE payload payload LONGTEXT NOT NULL');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE travel_snapshot CHANGE payload payload TEXT NOT NULL');
}
}
-27
View File
@@ -1,27 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260422120000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Store requested Mailjet list IDs on newsletter opt-in confirmations';
}
public function up(Schema $schema): void
{
$this->addSql("ALTER TABLE newsletter_opt_in_confirmation ADD mailjet_list_ids JSON DEFAULT NULL COMMENT '(DC2Type:json)'");
$this->addSql('UPDATE newsletter_opt_in_confirmation SET mailjet_list_ids = JSON_ARRAY(10321569) WHERE mailjet_list_ids IS NULL');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE newsletter_opt_in_confirmation DROP mailjet_list_ids');
}
}
-26
View File
@@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260423120000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Store optional first and last names on newsletter opt-in confirmations';
}
public function up(Schema $schema): void
{
$this->addSql("ALTER TABLE newsletter_opt_in_confirmation ADD first_name VARCHAR(255) DEFAULT NULL, ADD last_name VARCHAR(255) DEFAULT NULL");
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE newsletter_opt_in_confirmation DROP first_name, DROP last_name');
}
}
-26
View File
@@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260424110732 extends AbstractMigration
{
public function getDescription(): string
{
return 'Track newsletter revocations on opt-in confirmations';
}
public function up(Schema $schema): void
{
$this->addSql("ALTER TABLE newsletter_opt_in_confirmation ADD revoked_at DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)'");
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE newsletter_opt_in_confirmation DROP revoked_at');
}
}
-29
View File
@@ -1,29 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260429120000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Create per-list newsletter consent table and backfill confirmed opt-ins';
}
public function up(Schema $schema): void
{
$this->addSql("CREATE TABLE newsletter_consent (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(255) NOT NULL, mailjet_list_id INT NOT NULL, confirmed_at DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)', revoked_at DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)', first_name VARCHAR(255) DEFAULT NULL, last_name VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', updated_at DATETIME NOT NULL COMMENT '(DC2Type:datetime_immutable)', UNIQUE INDEX UNIQ_NEWSLETTER_CONSENT_EMAIL_LIST (email, mailjet_list_id), INDEX IDX_NEWSLETTER_CONSENT_EMAIL (email), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB");
$this->addSql("INSERT IGNORE INTO newsletter_consent (email, mailjet_list_id, confirmed_at, revoked_at, first_name, last_name, created_at, updated_at) SELECT email, 10321569, confirmed_at, revoked_at, first_name, last_name, created_at, COALESCE(confirmed_at, created_at) FROM newsletter_opt_in_confirmation WHERE confirmed_at IS NOT NULL AND (mailjet_list_ids IS NULL OR JSON_LENGTH(mailjet_list_ids) = 0)");
$this->addSql("INSERT IGNORE INTO newsletter_consent (email, mailjet_list_id, confirmed_at, revoked_at, first_name, last_name, created_at, updated_at) SELECT c.email, CAST(j.list_id AS UNSIGNED), c.confirmed_at, c.revoked_at, c.first_name, c.last_name, c.created_at, COALESCE(c.confirmed_at, c.created_at) FROM newsletter_opt_in_confirmation c JOIN JSON_TABLE(c.mailjet_list_ids, '$[*]' COLUMNS (list_id VARCHAR(32) PATH '$')) j WHERE c.confirmed_at IS NOT NULL");
$this->addSql('DELETE FROM newsletter_opt_in_confirmation WHERE confirmed_at IS NOT NULL');
}
public function down(Schema $schema): void
{
$this->addSql('DROP TABLE newsletter_consent');
}
}
-26
View File
@@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260429130000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Rename newsletter opt-in confirmation table to newsletter opt-in request';
}
public function up(Schema $schema): void
{
$this->addSql('RENAME TABLE newsletter_opt_in_confirmation TO newsletter_opt_in_request');
}
public function down(Schema $schema): void
{
$this->addSql('RENAME TABLE newsletter_opt_in_request TO newsletter_opt_in_confirmation');
}
}
-59
View File
@@ -1,59 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260625092525 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE accommodation (id INT AUTO_INCREMENT NOT NULL, created_by_id INT DEFAULT NULL, updated_by_id INT DEFAULT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(16) NOT NULL, min_pax_summer INT NOT NULL, max_adolescent_age INT NOT NULL, currency VARCHAR(3) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', UNIQUE INDEX UNIQ_2D38541277153098 (code), INDEX IDX_2D385412B03A8386 (created_by_id), INDEX IDX_2D385412896DBBDE (updated_by_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE accommodation_price (id INT AUTO_INCREMENT NOT NULL, accommodation_id INT NOT NULL, created_by_id INT DEFAULT NULL, updated_by_id INT DEFAULT NULL, date_from DATE NOT NULL COMMENT \'(DC2Type:date_immutable)\', date_to DATE NOT NULL COMMENT \'(DC2Type:date_immutable)\', included_pax INT NOT NULL, price_per_night INT NOT NULL, price_additional_person INT NOT NULL, min_nights INT NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_C67701238F3692CD (accommodation_id), INDEX IDX_C6770123B03A8386 (created_by_id), INDEX IDX_C6770123896DBBDE (updated_by_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE additional_service (id INT AUTO_INCREMENT NOT NULL, accommodation_id INT NOT NULL, created_by_id INT DEFAULT NULL, updated_by_id INT DEFAULT NULL, label VARCHAR(255) NOT NULL, price INT NOT NULL, type VARCHAR(20) NOT NULL, date_from DATE NOT NULL COMMENT \'(DC2Type:date_immutable)\', date_to DATE NOT NULL COMMENT \'(DC2Type:date_immutable)\', `grouping` VARCHAR(128) NOT NULL, sorting INT NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_E01749268F3692CD (accommodation_id), INDEX IDX_E0174926B03A8386 (created_by_id), INDEX IDX_E0174926896DBBDE (updated_by_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE board_service (id INT AUTO_INCREMENT NOT NULL, accommodation_id INT NOT NULL, created_by_id INT DEFAULT NULL, updated_by_id INT DEFAULT NULL, label VARCHAR(255) NOT NULL, price INT NOT NULL, date_from DATE NOT NULL COMMENT \'(DC2Type:date_immutable)\', date_to DATE NOT NULL COMMENT \'(DC2Type:date_immutable)\', sorting INT NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_A983B2DD8F3692CD (accommodation_id), INDEX IDX_A983B2DDB03A8386 (created_by_id), INDEX IDX_A983B2DD896DBBDE (updated_by_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE accommodation ADD CONSTRAINT FK_2D385412B03A8386 FOREIGN KEY (created_by_id) REFERENCES user (id) ON DELETE SET NULL');
$this->addSql('ALTER TABLE accommodation ADD CONSTRAINT FK_2D385412896DBBDE FOREIGN KEY (updated_by_id) REFERENCES user (id) ON DELETE SET NULL');
$this->addSql('ALTER TABLE accommodation_price ADD CONSTRAINT FK_C67701238F3692CD FOREIGN KEY (accommodation_id) REFERENCES accommodation (id)');
$this->addSql('ALTER TABLE accommodation_price ADD CONSTRAINT FK_C6770123B03A8386 FOREIGN KEY (created_by_id) REFERENCES user (id) ON DELETE SET NULL');
$this->addSql('ALTER TABLE accommodation_price ADD CONSTRAINT FK_C6770123896DBBDE FOREIGN KEY (updated_by_id) REFERENCES user (id) ON DELETE SET NULL');
$this->addSql('ALTER TABLE additional_service ADD CONSTRAINT FK_E01749268F3692CD FOREIGN KEY (accommodation_id) REFERENCES accommodation (id)');
$this->addSql('ALTER TABLE additional_service ADD CONSTRAINT FK_E0174926B03A8386 FOREIGN KEY (created_by_id) REFERENCES user (id) ON DELETE SET NULL');
$this->addSql('ALTER TABLE additional_service ADD CONSTRAINT FK_E0174926896DBBDE FOREIGN KEY (updated_by_id) REFERENCES user (id) ON DELETE SET NULL');
$this->addSql('ALTER TABLE board_service ADD CONSTRAINT FK_A983B2DD8F3692CD FOREIGN KEY (accommodation_id) REFERENCES accommodation (id)');
$this->addSql('ALTER TABLE board_service ADD CONSTRAINT FK_A983B2DDB03A8386 FOREIGN KEY (created_by_id) REFERENCES user (id) ON DELETE SET NULL');
$this->addSql('ALTER TABLE board_service ADD CONSTRAINT FK_A983B2DD896DBBDE FOREIGN KEY (updated_by_id) REFERENCES user (id) ON DELETE SET NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE accommodation DROP FOREIGN KEY FK_2D385412B03A8386');
$this->addSql('ALTER TABLE accommodation DROP FOREIGN KEY FK_2D385412896DBBDE');
$this->addSql('ALTER TABLE accommodation_price DROP FOREIGN KEY FK_C67701238F3692CD');
$this->addSql('ALTER TABLE accommodation_price DROP FOREIGN KEY FK_C6770123B03A8386');
$this->addSql('ALTER TABLE accommodation_price DROP FOREIGN KEY FK_C6770123896DBBDE');
$this->addSql('ALTER TABLE additional_service DROP FOREIGN KEY FK_E01749268F3692CD');
$this->addSql('ALTER TABLE additional_service DROP FOREIGN KEY FK_E0174926B03A8386');
$this->addSql('ALTER TABLE additional_service DROP FOREIGN KEY FK_E0174926896DBBDE');
$this->addSql('ALTER TABLE board_service DROP FOREIGN KEY FK_A983B2DD8F3692CD');
$this->addSql('ALTER TABLE board_service DROP FOREIGN KEY FK_A983B2DDB03A8386');
$this->addSql('ALTER TABLE board_service DROP FOREIGN KEY FK_A983B2DD896DBBDE');
$this->addSql('DROP TABLE accommodation');
$this->addSql('DROP TABLE accommodation_price');
$this->addSql('DROP TABLE additional_service');
$this->addSql('DROP TABLE board_service');
}
}
-31
View File
@@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260625154838 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE accommodation_price ADD price_per_night_override INT DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE accommodation_price DROP price_per_night_override');
}
}
-31
View File
@@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260625173941 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE additional_service ADD selection_group VARCHAR(128) DEFAULT NULL, DROP `grouping`');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE additional_service ADD `grouping` VARCHAR(128) NOT NULL, DROP selection_group');
}
}
-31
View File
@@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260627121823 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE accommodation_price ADD accept_undersubscription TINYINT(1) NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE accommodation_price DROP accept_undersubscription');
}
}
-31
View File
@@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260627130625 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE accommodation_price ADD price_additional_person_override INT DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE accommodation_price DROP price_additional_person_override');
}
}
-31
View File
@@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260630080409 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE accommodation_price ADD season VARCHAR(20) NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE accommodation_price DROP season');
}
}
-35
View File
@@ -1,35 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260630085856 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('DROP INDEX UNIQ_2D38541277153098 ON accommodation');
$this->addSql('ALTER TABLE accommodation ADD cms_code VARCHAR(16) DEFAULT NULL, CHANGE code calendar_code VARCHAR(16) NOT NULL');
$this->addSql('CREATE UNIQUE INDEX UNIQ_2D3854122583B3CC ON accommodation (calendar_code)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP INDEX UNIQ_2D3854122583B3CC ON accommodation');
$this->addSql('ALTER TABLE accommodation DROP cms_code, CHANGE calendar_code code VARCHAR(16) NOT NULL');
$this->addSql('CREATE UNIQUE INDEX UNIQ_2D38541277153098 ON accommodation (code)');
}
}
Loaded 100 of 810 files, more files were not shown because too many files have changed in this diff. Show more