Compare commits
685
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d74127ebe2 | ||
|
|
aa486a4931 | ||
|
|
7ebd2dad1a | ||
|
|
7a82127494 | ||
|
|
490acc2e8b | ||
|
|
6af8044f7c | ||
|
|
70a10c4dba | ||
|
|
a1506ef58d | ||
|
|
af04ff690d | ||
|
|
6c1073e41c | ||
|
|
124c0af0f5 | ||
|
|
212bb660a1 | ||
|
|
6ee00f2bee | ||
|
|
b82e017f73 | ||
|
|
577f7445ab | ||
|
|
3a5895e356 | ||
|
|
dd658bf9d6 | ||
|
|
aa8fa5c1b2 | ||
|
|
2cfa87f44b | ||
|
|
0b642dcfe4 | ||
|
|
8a46908856 | ||
|
|
736128476b | ||
|
|
8e4afc0813 | ||
|
|
e5fa63b7e8 | ||
|
|
84df3a94d9 | ||
|
|
2c381ee741 | ||
|
|
dc86e715cb | ||
|
|
5f2252af71 | ||
|
|
455456b6bc | ||
|
|
045fdea923 | ||
|
|
8ff13614d2 | ||
|
|
331c88c38e | ||
|
|
c31d086356 | ||
|
|
dde36ccba2 | ||
|
|
97d98f7f12 | ||
|
|
0546f223f0 | ||
|
|
6b807f358e | ||
|
|
6f84fc755b | ||
|
|
b54c8917c9 | ||
|
|
efc385bf54 | ||
|
|
18b59534f0 | ||
|
|
8a361ee703 | ||
|
|
0f1f65fb79 | ||
|
|
0b21bb00cb | ||
|
|
9d2aa11fdb | ||
|
|
eabed8295a | ||
|
|
7ec3903bdf | ||
|
|
c929d4da3b | ||
|
|
10d5356381 | ||
|
|
b323c120f9 | ||
|
|
fafc60eba9 | ||
|
|
bd2d8b58a3 | ||
|
|
52327864d6 | ||
|
|
3cc5d00587 | ||
|
|
f620cae4f9 | ||
|
|
6c4ea07e6e | ||
|
|
b95944701e | ||
|
|
2f8701c2e0 | ||
|
|
f47142c465 | ||
|
|
3105f2e7a0 | ||
|
|
0ea43d0c6b | ||
|
|
99b6876ce2 | ||
|
|
4e26b8acc0 | ||
|
|
0b2a16d117 | ||
|
|
b41b19d4c6 | ||
|
|
f9142e3080 | ||
|
|
9660149c67 | ||
|
|
2b957e1887 | ||
|
|
57a2503da2 | ||
|
|
f5f84ad98e | ||
|
|
de37186706 | ||
|
|
4d3fc69faa | ||
|
|
022819cbe6 | ||
|
|
1b0d7ce1a9 | ||
|
|
a6ed60462d | ||
|
|
a8d2852313 | ||
|
|
8907233ef5 | ||
|
|
7a3d3a3a96 | ||
|
|
23a3430ea5 | ||
|
|
a15c7578c3 | ||
|
|
08f6633507 | ||
|
|
dbe33ec760 | ||
|
|
145f7de781 | ||
|
|
287ec30cf7 | ||
|
|
c29634b0d2 | ||
|
|
ffa2038acb | ||
|
|
febbf8dd1d | ||
|
|
09610ab3cd | ||
|
|
33328074b0 | ||
|
|
1dc14a193a | ||
|
|
2fc7ffe458 | ||
|
|
52ee6b26b1 | ||
|
|
d77f92b6f0 | ||
|
|
e65cd3a96e | ||
|
|
80569e0977 | ||
|
|
66d0f511df | ||
|
|
93201fbd20 | ||
|
|
b2fccae431 | ||
|
|
8c99fba6fa | ||
|
|
d207bc74cb | ||
|
|
bcf75ce3c3 | ||
|
|
d08d9dbb9f | ||
|
|
33f0cb04e0 | ||
|
|
3fb95cab92 | ||
|
|
b768af15fe | ||
|
|
00889318ee | ||
|
|
f023bd9772 | ||
|
|
4ec1935eef | ||
|
|
ee8c6a6545 | ||
|
|
02b1cbfd6c | ||
|
|
97f88d5eeb | ||
|
|
5561a24050 | ||
|
|
bdf8cffd04 | ||
|
|
fa7e5c2091 | ||
|
|
f1a5d478f3 | ||
|
|
de4dadb9e5 | ||
|
|
b18b09d4a5 | ||
|
|
3f66cb89e6 | ||
|
|
495c130e79 | ||
|
|
7dfbc06bd1 | ||
|
|
132dfc6860 | ||
|
|
e647b6c1f0 | ||
|
|
8b3ef0df95 | ||
|
|
224673a2c4 | ||
|
|
eaff989bdd | ||
|
|
8ac62d2a02 | ||
|
|
1fa8f88a6d | ||
|
|
d211425ff2 | ||
|
|
5b16a515f3 | ||
|
|
259cbd02c5 | ||
|
|
014a057164 | ||
|
|
9ebfdb3d95 | ||
|
|
4f6b82daa8 | ||
|
|
77ad96baf9 | ||
|
|
68900dd4ea | ||
|
|
c0c8ad515c | ||
|
|
287c299c41 | ||
|
|
a2bcedafc4 | ||
|
|
daf89f9189 | ||
|
|
2f96af9254 | ||
|
|
18a97394e8 | ||
|
|
e4ef2f7adc | ||
|
|
df7885ca1c | ||
|
|
d5dfb6c550 | ||
|
|
9b84893d88 | ||
|
|
a1f68ec11d | ||
|
|
b9c6ace1da | ||
|
|
c1c7466dc7 | ||
|
|
02a1640b51 | ||
|
|
083e68ee4d | ||
|
|
4f7cd2c025 | ||
|
|
80969d1da0 | ||
|
|
5a0bf11c81 | ||
|
|
ca6e38cb9c | ||
|
|
ca5a604a3e | ||
|
|
0fcecc9c58 | ||
|
|
4e925171b3 | ||
|
|
41e2fe19bc | ||
|
|
a927d6bf59 | ||
|
|
c0cc183c59 | ||
|
|
b68c4ff9b4 | ||
|
|
132329361f | ||
|
|
4d86629315 | ||
|
|
d1c92f2957 | ||
|
|
0d2cc5b998 | ||
|
|
fdfd5d56c9 | ||
|
|
059c520a50 | ||
|
|
d8818dc435 | ||
|
|
2baa147afa | ||
|
|
e179bbe259 | ||
|
|
16cab4b768 | ||
|
|
6ab34fa87c | ||
|
|
fcfd366dec | ||
|
|
98dd685679 | ||
|
|
2597318488 | ||
|
|
aa997826f8 | ||
|
|
69705052b3 | ||
|
|
f903f17ebd | ||
|
|
95d50e9833 | ||
|
|
63e8a068b3 | ||
|
|
dbc0b4acee | ||
|
|
f31ac660d2 | ||
|
|
8b72f8c277 | ||
|
|
ca052682bb | ||
|
|
1b0e479e49 | ||
|
|
f22ceae41c | ||
|
|
346256f895 | ||
|
|
a0cbd5a23f | ||
|
|
803b0608cc | ||
|
|
7eb1cbdabd | ||
|
|
ca873a99f4 | ||
|
|
8d666baf28 | ||
|
|
be0c9d67bb | ||
|
|
f0594ba09c | ||
|
|
fce6d1615a | ||
|
|
a264526127 | ||
|
|
fbfffbb31a | ||
|
|
bca3610cff | ||
|
|
facd91375c | ||
|
|
96321005e0 | ||
|
|
6f07678f04 | ||
|
|
3b6ee90a7e | ||
|
|
909e8a1d8e | ||
|
|
8f2baca339 | ||
|
|
637166bfd6 | ||
|
|
45af3a21b7 | ||
|
|
7e686cef6b | ||
|
|
be43d30cc7 | ||
|
|
77b16f287a | ||
|
|
bc7fb794bf | ||
|
|
c1ab6d8687 | ||
|
|
ccfafc5da4 | ||
|
|
502281e219 | ||
|
|
b81cc58d5e | ||
|
|
05ac07d656 | ||
|
|
3234c78f0d | ||
|
|
3849ae306c | ||
|
|
301b14f518 | ||
|
|
df8566e1b5 | ||
|
|
45d05786da | ||
|
|
6a6bebb2d1 | ||
|
|
ea76c808de | ||
|
|
f9069540a9 | ||
|
|
8a9868b644 | ||
|
|
d1e2bf3e7d | ||
|
|
66c55f0722 | ||
|
|
ca7d0b6965 | ||
|
|
02ff28acdd | ||
|
|
cb56a4fe46 | ||
|
|
752e6752b4 | ||
|
|
00df76269a | ||
|
|
99483b3506 | ||
|
|
5619a6f22f | ||
|
|
c510cbf590 | ||
|
|
6d9265de0f | ||
|
|
49ea562322 | ||
|
|
1f087b6c08 | ||
|
|
37c839600e | ||
|
|
cef2e4fa49 | ||
|
|
11ff2b9084 | ||
|
|
69f16b59cb | ||
|
|
0e644260b6 | ||
|
|
33609ab534 | ||
|
|
1cc7a025a1 | ||
|
|
709b0ff61e | ||
|
|
0d7d90a442 | ||
|
|
5cbdc5eaf2 | ||
|
|
a7c3064df6 | ||
|
|
f63d52c9d6 | ||
|
|
b752256bda | ||
|
|
474d171779 | ||
|
|
51ce9b6e45 | ||
|
|
9cef24f827 | ||
|
|
e6880b7fed | ||
|
|
e505eba111 | ||
|
|
4e067d13b3 | ||
|
|
40c0042158 | ||
|
|
6abfa122e4 | ||
|
|
032540a712 | ||
|
|
cf95048f2b | ||
|
|
29a1ce7de7 | ||
|
|
1670b8b8d2 | ||
|
|
3644b935fd | ||
|
|
20162cceef | ||
|
|
44a9de7db7 | ||
|
|
f99a2d99a2 | ||
|
|
f795a3ea21 | ||
|
|
f8a56b7de2 | ||
|
|
8a667ccaba | ||
|
|
6ddd0b00bd | ||
|
|
c597cfda51 | ||
|
|
f673bc59d0 | ||
|
|
78b925daa6 | ||
|
|
4e05c94912 | ||
|
|
acb599b760 | ||
|
|
c7b70dbd56 | ||
|
|
b4f7299f27 | ||
|
|
6fd5a218a3 | ||
|
|
a1518c06fb | ||
|
|
c517a0b41f | ||
|
|
ded904fac8 | ||
|
|
abea6bff7b | ||
|
|
06f53ba6eb | ||
|
|
eda0919f52 | ||
|
|
1f27c744d2 | ||
|
|
bbc011ddb9 | ||
|
|
c2054a1ef6 | ||
|
|
f9d420fecd | ||
|
|
3e1d719512 | ||
|
|
f685bd18ab | ||
|
|
f46cc59041 | ||
|
|
380b1ed329 | ||
|
|
1056b4fba6 | ||
|
|
19031dba99 | ||
|
|
028db7a7ee | ||
|
|
a1764faaeb | ||
|
|
8529bb0e21 | ||
|
|
9eefdd1858 | ||
|
|
e5803860df | ||
|
|
2754d734aa | ||
|
|
3487ca4822 | ||
|
|
02ebddc34a | ||
|
|
3957f6bd09 | ||
|
|
11ab98b3d8 | ||
|
|
e24403949c | ||
|
|
288f6b91d0 | ||
|
|
8ca105966d | ||
|
|
592cd517ff | ||
|
|
586b410a66 | ||
|
|
a444940db2 | ||
|
|
afe5aef9f7 | ||
|
|
21a3e8fafc | ||
|
|
26bbba5a2e | ||
|
|
b68d5c9398 | ||
|
|
c1425f0562 | ||
|
|
e1f1b60608 | ||
|
|
ea1c95528c | ||
|
|
0cac2969ae | ||
|
|
b856c51389 | ||
|
|
aa3b23ecb8 | ||
|
|
1e653e213a | ||
|
|
7d91dcfb70 | ||
|
|
8e7e6266f0 | ||
|
|
167ccf5151 | ||
|
|
c582e0820a | ||
|
|
7d3a63d744 | ||
|
|
0a0987873f | ||
|
|
18d60c8781 | ||
|
|
7708ea6a0f | ||
|
|
71a46c6b63 | ||
|
|
667324df69 | ||
|
|
957e20d763 | ||
|
|
029a87c6ca | ||
|
|
baa4609102 | ||
|
|
875943e4da | ||
|
|
10e674cdd0 | ||
|
|
0bf78b0b81 | ||
|
|
c90b93556a | ||
|
|
f45718ea06 | ||
|
|
6d418ee8cc | ||
|
|
4851b1b72d | ||
|
|
dfb6f88be9 | ||
|
|
f28227384d | ||
|
|
cef9be92f3 | ||
|
|
f849d67a79 | ||
|
|
fba3becb06 | ||
|
|
a23ff6d119 | ||
|
|
384744c958 | ||
|
|
70c6617e88 | ||
|
|
9afe3b334e | ||
|
|
ad67d4c7ae | ||
|
|
b7eaed3ac3 | ||
|
|
136e2d68a2 | ||
|
|
bdcd54687d | ||
|
|
99190b0ef1 | ||
|
|
c7702b0c37 | ||
|
|
9b88a2c14d | ||
|
|
6a945e6a08 | ||
|
|
9c7cf0778f | ||
|
|
dd0f1a25d0 | ||
|
|
7f4cf3060e | ||
|
|
30496a4875 | ||
|
|
027508f495 | ||
|
|
b5e2b2a2ad | ||
|
|
9c9db05b86 | ||
|
|
1fa17a7df7 | ||
|
|
e09e5858d8 | ||
|
|
6ede062a66 | ||
|
|
b351b4042f | ||
|
|
95d0ce33d4 | ||
|
|
75366167e8 | ||
|
|
7fa7e4be45 | ||
|
|
d14dafbade | ||
|
|
e222f448bb | ||
|
|
f55ed3dc4c | ||
|
|
fedfcc247e | ||
|
|
8186adfaeb | ||
|
|
00304facba | ||
|
|
ff241f437f | ||
|
|
4a6b9cd64d | ||
|
|
8646dfbf02 | ||
|
|
d6f2681c61 | ||
|
|
5a47ca6053 | ||
|
|
d7fd273475 | ||
|
|
ce828a6ef5 | ||
|
|
15dbd72f93 | ||
|
|
e3bdd8737f | ||
|
|
7942656026 | ||
|
|
1fe8a2cb17 | ||
|
|
ab48b1f867 | ||
|
|
3043842254 | ||
|
|
249e326de4 | ||
|
|
b3cace3b43 | ||
|
|
ad578179d8 | ||
|
|
c57351f8b5 | ||
|
|
c5934e4c5b | ||
|
|
06e64bd3b8 | ||
|
|
48572812a9 | ||
|
|
46b610370a | ||
|
|
96d4b8ed45 | ||
|
|
c18ba3d815 | ||
|
|
fd81079247 | ||
|
|
e5781fbabc | ||
|
|
8887b06583 | ||
|
|
9955ff7df9 | ||
|
|
db74b6049c | ||
|
|
0b5c7af4be | ||
|
|
721016a00e | ||
|
|
563522d261 | ||
|
|
04f4455491 | ||
|
|
b976ce480a | ||
|
|
6d5f7cfd22 | ||
|
|
9baed0987e | ||
|
|
b76d17d35c | ||
|
|
4e182612e8 | ||
|
|
645729a518 | ||
|
|
9ee4c1cd5c | ||
|
|
02742aef5b | ||
|
|
87af2c3855 | ||
|
|
ea1ce4a029 | ||
|
|
2fe9185a6f | ||
|
|
ef191c55be | ||
|
|
abd74a127a | ||
|
|
52ac269b8d | ||
|
|
643f65ce3b | ||
|
|
465ce3e69a | ||
|
|
207b648f36 | ||
|
|
7f2d52a5ce | ||
|
|
f1eaa95c44 | ||
|
|
e203de172d | ||
|
|
79b7e2aaa5 | ||
|
|
3c2ade9299 | ||
|
|
f3f2dc6cec | ||
|
|
12b69bd681 | ||
|
|
8f542ff448 | ||
|
|
80c81c11fb | ||
|
|
e3809bd930 | ||
|
|
d755e29459 | ||
|
|
105eb5a9cd | ||
|
|
65f8436aa7 | ||
|
|
4afdd79252 | ||
|
|
d1e807b11f | ||
|
|
ee84690cd9 | ||
|
|
c7a27f1dc7 | ||
|
|
1fd9f8d1f8 | ||
|
|
b57d849ecd | ||
|
|
654ae4dc0b | ||
|
|
3984a623bf | ||
|
|
96619c6cec | ||
|
|
3dd92ccdb4 | ||
|
|
b111a615a9 | ||
|
|
2372958713 | ||
|
|
82a8541af1 | ||
|
|
ea162972fa | ||
|
|
094d6858d1 | ||
|
|
65398d59d4 | ||
|
|
3df9659ce2 | ||
|
|
c4f4f53fd6 | ||
|
|
b567b6a840 | ||
|
|
ab18e5f134 | ||
|
|
929115c02b | ||
|
|
e26884c099 | ||
|
|
077bcdcaf5 | ||
|
|
685ac5a94a | ||
|
|
3d1b75b591 | ||
|
|
e1bfe9b93c | ||
|
|
5b75a165ce | ||
|
|
e12fbc85d4 | ||
|
|
6bbef0a975 | ||
|
|
bc175ca438 | ||
|
|
ef15772b97 | ||
|
|
da5b913757 | ||
|
|
6b5a51f652 | ||
|
|
af2620c8b3 | ||
|
|
15fdfdc42e | ||
|
|
ce88e1f97b | ||
|
|
a67e3a5eac | ||
|
|
cc747f0690 | ||
|
|
a6d2661562 | ||
|
|
4b95b12a7b | ||
|
|
cca8554e3d | ||
|
|
28c426ca3c | ||
|
|
be83a4295a | ||
|
|
87439ee509 | ||
|
|
36ef54d541 | ||
|
|
400407358d | ||
|
|
502b121e43 | ||
|
|
61447ced4f | ||
|
|
1e107c68b4 | ||
|
|
602fb31f27 | ||
|
|
2a8531a025 | ||
|
|
980589e190 | ||
|
|
4a2d1f4a02 | ||
|
|
39e6cc4d68 | ||
|
|
e5018432cb | ||
|
|
dbf0b03bac | ||
|
|
01060035bc | ||
|
|
fa0cf5a654 | ||
|
|
4f1a1cad8e | ||
|
|
8c8aae9a1e | ||
|
|
230c53875f | ||
|
|
2e40cbc7c7 | ||
|
|
cd1ffc3e9a | ||
|
|
4db2cd7eda | ||
|
|
f230b36382 | ||
|
|
b872f2a5db | ||
|
|
c6678d16a6 | ||
|
|
b73a02048e | ||
|
|
1f2f2751e4 | ||
|
|
85998534fe | ||
|
|
8e7b8bd75f | ||
|
|
fb983f23dd | ||
|
|
7df99521c4 | ||
|
|
a8c0a1aa61 | ||
|
|
fc05350ae4 | ||
|
|
ba7de8fa01 | ||
|
|
778cf80e6b | ||
|
|
f01bb7d271 | ||
|
|
6a031e5a71 | ||
|
|
37924841e1 | ||
|
|
be90248fc7 | ||
|
|
cb38beb32c | ||
|
|
cc8500d0f4 | ||
|
|
61d4e36f1f | ||
|
|
5c5f164aa2 | ||
|
|
5275e6c732 | ||
|
|
f3ea6734a1 | ||
|
|
bb20176c76 | ||
|
|
beee44a10e | ||
|
|
43823dbda1 | ||
|
|
ff39bf365c | ||
|
|
5d69e4a8aa | ||
|
|
142db19627 | ||
|
|
7b84ecbb56 | ||
|
|
dc6de1734a | ||
|
|
1e464cef0a | ||
|
|
4decaa6789 | ||
|
|
a057088808 | ||
|
|
e46053a7b7 | ||
|
|
91d9e82d84 | ||
|
|
608f5ed3e9 | ||
|
|
9b2e209b4f | ||
|
|
bae1582631 | ||
|
|
c3fe76d78c | ||
|
|
8abab0e379 | ||
|
|
d31204188b | ||
|
|
a74f34b559 | ||
|
|
37cda348b0 | ||
|
|
38656e73c5 | ||
|
|
03ac430be4 | ||
|
|
89979d6ce4 | ||
|
|
54a3145710 | ||
|
|
7aea149b6c | ||
|
|
f50aa55e8b | ||
|
|
6c0d7c30c6 | ||
|
|
af163d597e | ||
|
|
d0c8302d21 | ||
|
|
44e2d76525 | ||
|
|
8f274bbb44 | ||
|
|
8436124cbc | ||
|
|
647fa8e212 | ||
|
|
6cc5886073 | ||
|
|
513c889926 | ||
|
|
9c6f4d59b3 | ||
|
|
a0d5768752 | ||
|
|
4f951cdf8a | ||
|
|
619e2ba1ee | ||
|
|
7d6a80eefa | ||
|
|
2403f8fb29 | ||
|
|
b485112ed3 | ||
|
|
1f5c835f8a | ||
|
|
a3d7ee63d3 | ||
|
|
a8cf67728b | ||
|
|
c830fc7841 | ||
|
|
5ef3bb9cbf | ||
|
|
b882175f36 | ||
|
|
d20215929d | ||
|
|
ea312b9986 | ||
|
|
0559341f31 | ||
|
|
1f4dc2d4a2 | ||
|
|
14ca0f5c59 | ||
|
|
e51c4843c5 | ||
|
|
32a9fac9ed | ||
|
|
de8cbf6178 | ||
|
|
33e1aea80c | ||
|
|
83589ee677 | ||
|
|
023ecdebc9 | ||
|
|
2d9cb2c0b9 | ||
|
|
5c0814ef9b | ||
|
|
28831a3b06 | ||
|
|
0d073a36a3 | ||
|
|
069600d602 | ||
|
|
d70a27f2fd | ||
|
|
e330626b03 | ||
|
|
0f4b16c194 | ||
|
|
c89bda86b7 | ||
|
|
56fa5355fd | ||
|
|
7ea52670b9 | ||
|
|
ee264e88d4 | ||
|
|
3f7db4e772 | ||
|
|
3d9fc18a83 | ||
|
|
9eeed7f992 | ||
|
|
ba0a86cbea | ||
|
|
41d8d65d82 | ||
|
|
57843b8a6f | ||
|
|
d6258d0ca1 | ||
|
|
66ccebb02b | ||
|
|
e3081e56f8 | ||
|
|
201b223813 | ||
|
|
08d534e39b | ||
|
|
4489169553 | ||
|
|
16c239716b | ||
|
|
f5913eb947 | ||
|
|
f2681af9ee | ||
|
|
66dd51d75a | ||
|
|
5f78361533 | ||
|
|
3c1192298b | ||
|
|
0bd9d79bbe | ||
|
|
a2e055f313 | ||
|
|
ca1d5c4303 | ||
|
|
e6eebc00a3 | ||
|
|
29bdf794f3 | ||
|
|
4ba81b8f03 | ||
|
|
8af7f0e797 | ||
|
|
c67fa18ad3 | ||
|
|
6c9da6537e | ||
|
|
241785b428 | ||
|
|
411166ffba | ||
|
|
203c9ebbca | ||
|
|
ede37d5d0f | ||
|
|
4f02529b15 | ||
|
|
0f6b73340e | ||
|
|
96c53cc173 | ||
|
|
7ce3bc18b2 | ||
|
|
82b47e314b | ||
|
|
9d2474c1e3 | ||
|
|
787f69fc46 | ||
|
|
054d4e52b2 | ||
|
|
0d1ef6d40e | ||
|
|
ead448b8d4 | ||
|
|
7ff10e6792 | ||
|
|
3d6c94e7c5 | ||
|
|
7673e64738 | ||
|
|
4230c53812 | ||
|
|
3198e03cc4 | ||
|
|
1e48e107fc | ||
|
|
ed7c889c4f | ||
|
|
84f4481ef0 | ||
|
|
b84997d058 | ||
|
|
3063a7c05f | ||
|
|
36fe4c9e9a | ||
|
|
5c5134b69f | ||
|
|
e7fb764158 | ||
|
|
fe624cfd1c | ||
|
|
81b8237570 | ||
|
|
a019c7dae0 | ||
|
|
552dd029fa | ||
|
|
bd5c6359fe | ||
|
|
6bd483d768 | ||
|
|
7003c0d81b | ||
|
|
b038d9a41f | ||
|
|
89c42cf7e4 | ||
|
|
cd1e5ad3ad | ||
|
|
f36c761c28 | ||
|
|
0f7d95d31b | ||
|
|
4b92f56ed7 | ||
|
|
b54fb07e84 | ||
|
|
11825191cf | ||
|
|
d719b17aec | ||
|
|
65a33922cf | ||
|
|
727ee9b014 | ||
|
|
4d51f0334f | ||
|
|
86e4866d6a | ||
|
|
e75276ed88 | ||
|
|
bfdf4c0453 | ||
|
|
f90902c5e3 | ||
|
|
d0d6844fbd | ||
|
|
cd7a724e62 | ||
|
|
1f5877460b | ||
|
|
8da77ee13b | ||
|
|
d205cd09ef | ||
|
|
b44d8505b2 | ||
|
|
9d99fe9272 | ||
|
|
431839d36d | ||
|
|
cce1f688b9 |
No files matched your search
@@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
## Description: Run Claude Code
|
||||
## Usage: claude [args]
|
||||
## Example: ddev claude
|
||||
## Example: ddev claude --help
|
||||
## Example: ddev claude doctor
|
||||
|
||||
# Ensure ~/.local/bin is in PATH
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
|
||||
# Check if claude is installed
|
||||
if [ ! -f "$HOME/.local/bin/claude" ]; then
|
||||
echo "Claude Code is not installed. Installing now..."
|
||||
curl -fsSL https://claude.ai/install.sh | bash
|
||||
fi
|
||||
|
||||
# Run claude with all arguments
|
||||
exec "$HOME/.local/bin/claude" "$@"
|
||||
@@ -40,6 +40,27 @@ 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=
|
||||
@@ -55,20 +76,37 @@ APP_TERMS_AND_CONDITIONS_URL="https://www.ep-reisen.de/skireisen/infos/allgemein
|
||||
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=
|
||||
@@ -76,6 +114,11 @@ 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
|
||||
|
||||
@@ -4,3 +4,4 @@ APP_SECRET='$ecretf0rt3st'
|
||||
SYMFONY_DEPRECATIONS_HELPER=999999
|
||||
PANTHER_APP_ENV=panther
|
||||
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
|
||||
MAILJET_WEBHOOK_BASIC_PASSWORD=secret
|
||||
@@ -33,3 +33,7 @@ yarn-error.log
|
||||
###< friendsofphp/php-cs-fixer ###
|
||||
|
||||
/ray.php
|
||||
|
||||
###> phpstan/phpstan ###
|
||||
phpstan.neon
|
||||
###< phpstan/phpstan ###
|
||||
@@ -60,7 +60,7 @@ Authorization: Bearer {{$auth.token("oauth2_api")}}
|
||||
|
||||
### API travel
|
||||
# @no-cookie-jar
|
||||
GET {{base_url}}/api/travels/SBW131225
|
||||
GET {{base_url}}/api/travels/DPWMP140326
|
||||
Accept: application/json
|
||||
Authorization: Bearer {{$auth.token("oauth2_api")}}
|
||||
|
||||
@@ -100,6 +100,40 @@ Authorization: Bearer {{$auth.token("oauth2_api")}}
|
||||
"phone": "{{$random.phoneNumber.cellPhone}}"
|
||||
}
|
||||
|
||||
### 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
|
||||
@@ -115,3 +149,10 @@ 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")}}
|
||||
@@ -0,0 +1,8 @@
|
||||
import htmx from 'htmx.org'
|
||||
htmx.config.includeIndicatorStyles = false
|
||||
htmx.config.historyCacheSize = 0
|
||||
htmx.config.allowScriptTags = false
|
||||
|
||||
import './bootstrap.js'
|
||||
|
||||
import './styles/admin.css'
|
||||
@@ -13,3 +13,12 @@ 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
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,84 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
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')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
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 })
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Controller } from '@hotwired/stimulus'
|
||||
import tippy from 'tippy.js'
|
||||
import tippy, { hideAll } from 'tippy.js'
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ['trigger', 'template']
|
||||
@@ -27,6 +27,7 @@ export default class extends Controller {
|
||||
allowHTML: true,
|
||||
interactive: true,
|
||||
appendTo: document.body,
|
||||
onShow(instance) { hideAll({ exclude: instance }) },
|
||||
}
|
||||
}
|
||||
if (this.hasTriggerTarget) {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 839 KiB |
@@ -0,0 +1,94 @@
|
||||
<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-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>
|
||||
|
After Width: | Height: | Size: 55 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
@@ -0,0 +1 @@
|
||||
<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
|
||||
|
After Width: | Height: | Size: 8.4 KiB |
@@ -0,0 +1 @@
|
||||
<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
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
@@ -0,0 +1,29 @@
|
||||
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'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -53,6 +53,10 @@
|
||||
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%);;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
@import "components/typography.css";
|
||||
@import "components/forms.css";
|
||||
@import "components/button.css";
|
||||
@import "components/tooltip.css";
|
||||
@import "components/toast.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";
|
||||
@@ -0,0 +1,10 @@
|
||||
@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";
|
||||
@@ -0,0 +1,7 @@
|
||||
@import "tailwindcss/base";
|
||||
@import "_base.css";
|
||||
|
||||
@import "tailwindcss/components";
|
||||
@import "_components_admin.css";
|
||||
|
||||
@import "tailwindcss/utilities";
|
||||
@@ -0,0 +1,33 @@
|
||||
.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;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
.badge {
|
||||
@apply inline-flex items-center rounded-md px-1.5 py-0.5 text-xs font-medium whitespace-nowrap;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
.button {
|
||||
@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 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 rounded-md;
|
||||
}
|
||||
|
||||
@@ -20,42 +20,52 @@
|
||||
}
|
||||
|
||||
.button--secondary {
|
||||
@apply bg-none bg-primary-dark text-white;
|
||||
@apply hover:bg-primary-light/80;
|
||||
@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;
|
||||
}
|
||||
|
||||
.sbw {
|
||||
.button--primary {
|
||||
@apply bg-none bg-sbw-secondary text-white;
|
||||
@apply hover:bg-none hover:bg-sbw-primary/80;
|
||||
@apply hover:bg-none hover:bg-sbw-primary/50;
|
||||
}
|
||||
|
||||
.button--secondary {
|
||||
@apply bg-none bg-sbw-primary-dark text-white;
|
||||
@apply hover:bg-none hover:bg-sbw-primary/80;
|
||||
@apply hover:bg-none hover:bg-sbw-primary/50;
|
||||
}
|
||||
}
|
||||
|
||||
.snz {
|
||||
.button--primary {
|
||||
@apply bg-none bg-snz-secondary text-white;
|
||||
@apply hover:bg-none hover:bg-snz-primary/80;
|
||||
@apply hover:bg-none hover:bg-snz-primary/50;
|
||||
}
|
||||
|
||||
.button--secondary {
|
||||
@apply bg-none bg-snz-primary-dark text-white;
|
||||
@apply hover:bg-none hover:bg-snz-primary/80;
|
||||
@apply hover:bg-none hover:bg-snz-primary/50;
|
||||
}
|
||||
}
|
||||
|
||||
.ser {
|
||||
.button--primary {
|
||||
@apply bg-none bg-ser-secondary text-white;
|
||||
@apply hover:bg-none hover:bg-ser-primary/80;
|
||||
@apply hover:bg-none hover:bg-ser-primary/50;
|
||||
}
|
||||
|
||||
.button--secondary {
|
||||
@apply bg-none bg-ser-primary text-white;
|
||||
@apply hover:bg-none hover:bg-ser-primary/80;
|
||||
@apply hover:bg-none hover:bg-ser-primary/50;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
.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;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
@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');
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
@import "glightbox/dist/css/glightbox.min.css";
|
||||
@@ -0,0 +1,41 @@
|
||||
.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;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
.rte-content {
|
||||
p {
|
||||
@apply pb-4;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply list-disc p-4;
|
||||
}
|
||||
|
||||
ol {
|
||||
@apply list-decimal p-4;
|
||||
}
|
||||
}
|
||||
+11
-3
@@ -14,8 +14,10 @@
|
||||
"doctrine/doctrine-bundle": "^2.13",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.3",
|
||||
"doctrine/orm": "^3.3",
|
||||
"easycorp/easyadmin-bundle": "^4.27",
|
||||
"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",
|
||||
@@ -54,6 +56,7 @@
|
||||
"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",
|
||||
@@ -61,6 +64,7 @@
|
||||
"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"
|
||||
},
|
||||
@@ -95,6 +99,8 @@
|
||||
"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"
|
||||
@@ -119,9 +125,11 @@
|
||||
"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",
|
||||
"spatie/ray": "^1.43",
|
||||
"spatie/x-ray": "^1.2",
|
||||
"rector/rector": "^2.4",
|
||||
"symfony/browser-kit": "6.4.*",
|
||||
"symfony/css-selector": "6.4.*",
|
||||
"symfony/debug-bundle": "6.4.*",
|
||||
|
||||
Generated
+1508
-1432
File diff suppressed because it is too large.
Load diff
+3
-1
@@ -16,6 +16,8 @@ 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],
|
||||
EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle::class => ['all' => true],
|
||||
];
|
||||
@@ -0,0 +1,2 @@
|
||||
flagception:
|
||||
features: {}
|
||||
@@ -1,21 +1,17 @@
|
||||
flysystem:
|
||||
storages:
|
||||
xml_export.storage:
|
||||
adapter: 'local'
|
||||
options:
|
||||
local:
|
||||
directory: '%env(resolve:XML_EXPORT_PATH)%'
|
||||
xml_source.storage:
|
||||
adapter: 'sftp'
|
||||
options:
|
||||
sftp:
|
||||
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:
|
||||
adapter: 'local'
|
||||
options:
|
||||
local:
|
||||
directory: '%kernel.project_dir%/var/bpn'
|
||||
json_export.storage:
|
||||
adapter: 'local'
|
||||
options:
|
||||
local:
|
||||
directory: '%env(resolve:JSON_EXPORT_PATH)%'
|
||||
@@ -9,9 +9,8 @@ framework:
|
||||
# Remove or comment this section to explicitly disable session support.
|
||||
session:
|
||||
handler_id: null
|
||||
cookie_secure: auto
|
||||
# cookie_samesite: lax
|
||||
cookie_samesite: none # this is to make login work in staging environment. to be removed when going live!
|
||||
cookie_secure: true
|
||||
cookie_samesite: lax
|
||||
|
||||
#esi: true
|
||||
#fragments: true
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
knp_menu:
|
||||
twig:
|
||||
template: _partials/_menu.html.twig
|
||||
@@ -0,0 +1,11 @@
|
||||
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'
|
||||
@@ -3,10 +3,12 @@ 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: false
|
||||
enable_refresh_token_grant: true
|
||||
enable_password_grant: false
|
||||
enable_implicit_grant: false
|
||||
access_token_ttl: PT10M
|
||||
resource_server:
|
||||
public_key: '%env(resolve:OAUTH_PUBLIC_KEY)%'
|
||||
@@ -15,6 +17,8 @@ league_oauth2_server:
|
||||
default: ['email']
|
||||
persistence:
|
||||
doctrine: null
|
||||
client:
|
||||
allow_plaintext_secrets: false
|
||||
|
||||
when@test:
|
||||
league_oauth2_server:
|
||||
|
||||
@@ -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,9 +21,10 @@ framework:
|
||||
messenger.bus.default: []
|
||||
|
||||
routing:
|
||||
Symfony\Component\Mailer\Messenger\SendEmailMessage: async
|
||||
Symfony\Component\Mailer\Messenger\SendEmailMessage: sync
|
||||
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
|
||||
@@ -4,6 +4,7 @@ monolog:
|
||||
- bpn
|
||||
- core
|
||||
- auth
|
||||
- admin
|
||||
|
||||
when@dev:
|
||||
monolog:
|
||||
@@ -27,11 +28,16 @@ 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"]
|
||||
channels: ["!event", "!bpn", "!core", "!auth", "!admin"]
|
||||
# uncomment to get logging in your browser
|
||||
# you may have to allow bigger header sizes in your Web server configuration
|
||||
#firephp:
|
||||
@@ -59,7 +65,7 @@ when@test:
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||
level: debug
|
||||
|
||||
when@prod:
|
||||
when@prod: &prod_config
|
||||
monolog:
|
||||
handlers:
|
||||
database:
|
||||
@@ -84,13 +90,19 @@ when@prod:
|
||||
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"]
|
||||
channels: ["!bpn", "!core", "!auth", "!admin"]
|
||||
nested:
|
||||
type: rotating_file
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.framework.log"
|
||||
@@ -104,4 +116,6 @@ when@prod:
|
||||
type: stream
|
||||
channels: [deprecation]
|
||||
path: php://stderr
|
||||
formatter: monolog.formatter.json
|
||||
formatter: monolog.formatter.json
|
||||
|
||||
when@staging: *prod_config
|
||||
@@ -1,6 +1,7 @@
|
||||
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:
|
||||
@@ -8,6 +9,17 @@ 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_GROUPS_ADMIN:
|
||||
- ROLE_GROUPS_MANAGER
|
||||
-
|
||||
firewalls:
|
||||
dev:
|
||||
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||
@@ -19,7 +31,15 @@ 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
|
||||
@@ -32,8 +52,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: ^/admin, roles: ROLE_ADMIN, requires_channel: https }
|
||||
- { path: ^/, roles: PUBLIC_ACCESS, requires_channel: https }
|
||||
|
||||
when@test:
|
||||
@@ -43,6 +63,7 @@ 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
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
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)%'
|
||||
@@ -8,6 +10,7 @@ twig:
|
||||
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:
|
||||
|
||||
@@ -24,6 +24,22 @@ zenstruck_schedule:
|
||||
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:
|
||||
@@ -37,8 +53,8 @@ when@prod:
|
||||
tasks:
|
||||
- task: app:bpn:xml-sync
|
||||
frequency: "*/15 8-19 * * *"
|
||||
description: "Sync BusPro XML data every 15 min. during peak hours"
|
||||
description: "Syncs 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"
|
||||
description: "Syncs BusPro XML data hourly outside peak hours"
|
||||
@@ -1,3 +0,0 @@
|
||||
easyadmin:
|
||||
resource: .
|
||||
type: easyadmin.routes
|
||||
+191
-28
@@ -9,26 +9,69 @@ parameters:
|
||||
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)%'
|
||||
|
||||
# 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': '195+'
|
||||
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': '95+'
|
||||
# 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:
|
||||
@@ -95,21 +138,73 @@ 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\TravelDataService:
|
||||
App\Service\TravelSnapshotManager:
|
||||
arguments:
|
||||
$retentionBufferDays: '%travel_snapshot_retention_buffer_days%'
|
||||
|
||||
App\Service\TravelDataProvider:
|
||||
arguments:
|
||||
$logger: '@monolog.logger.core'
|
||||
$preferRemote: '%env(bool:APP_TRAVEL_PREFER_REMOTE)%'
|
||||
$enableFallback: '%env(bool:APP_TRAVEL_ENABLE_FALLBACK)%'
|
||||
|
||||
App\Service\BookingEditDataLoaderService:
|
||||
App\Service\ParticipantFormSupport:
|
||||
arguments:
|
||||
$bodyDimensionRanges: '%body_dimension_ranges%'
|
||||
|
||||
App\Service\BookingEditDataLoader:
|
||||
arguments:
|
||||
$bpnCache: '@bpn.cache'
|
||||
|
||||
App\Service\VoucherValidationService:
|
||||
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:
|
||||
arguments:
|
||||
$cache: '@cache.app'
|
||||
$logger: '@monolog.logger.bpn'
|
||||
@@ -126,38 +221,41 @@ 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'
|
||||
|
||||
# Participant Status Rules
|
||||
# Booking Status Rules
|
||||
App\BusProNet\Service\StatusRule\Selection1473StatusRule: ~
|
||||
App\BusProNet\Service\StatusRule\ChaperonServiceStatusRule: ~
|
||||
|
||||
# Participant Status Rule Registry
|
||||
App\BusProNet\Service\ParticipantStatusRuleRegistry:
|
||||
# Booking Status Rule Registry
|
||||
App\BusProNet\Service\BookingStatusRuleRegistry:
|
||||
arguments:
|
||||
$rules:
|
||||
- '@App\BusProNet\Service\StatusRule\Selection1473StatusRule'
|
||||
- '@App\BusProNet\Service\StatusRule\ChaperonServiceStatusRule'
|
||||
|
||||
App\Service\CmsDataService:
|
||||
App\Service\CmsDataProvider:
|
||||
arguments:
|
||||
$httpClient: '@typo3.client'
|
||||
$apiKey: 'AbcAbc123'# dummy key, not yet implemented
|
||||
@@ -166,7 +264,72 @@ services:
|
||||
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%'
|
||||
+1
-1
@@ -2,7 +2,7 @@ const {defineConfig} = require("cypress");
|
||||
|
||||
module.exports = defineConfig({
|
||||
e2e: {
|
||||
baseUrl: 'https://myep-next-booking.ddev.site',
|
||||
baseUrl: 'https://myep.ddev.site',
|
||||
supportFile: false,
|
||||
},
|
||||
});
|
||||
+23
-2
@@ -101,7 +101,27 @@ host('staging')
|
||||
->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')
|
||||
->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',
|
||||
])
|
||||
;
|
||||
|
||||
task('deploy', [
|
||||
@@ -121,7 +141,8 @@ task('deploy', [
|
||||
]);
|
||||
|
||||
task('deploy:assets', function () {
|
||||
runLocally('npm ci && npm run build');
|
||||
runLocally('ddev exec npm ci');
|
||||
runLocally('ddev exec npm run build');
|
||||
});
|
||||
|
||||
task('deploy:stop-workers', function () {
|
||||
|
||||
@@ -1,484 +0,0 @@
|
||||
# Symfony 7.4 Upgrade Plan
|
||||
|
||||
**Project:** MyEP Next Booking
|
||||
**Current Version:** Symfony 6.4.x (6.4.33)
|
||||
**Target Version:** Symfony 7.4 (LTS)
|
||||
**Date:** 2026-02-23
|
||||
**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.3.30)
|
||||
- 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.3.30 (compatible; Symfony 7.4 requires 8.2+)
|
||||
- OAuth2 Server Bundle: 1.1.0 (compatible)
|
||||
- Stimulus Bundle: 2.32.0 (compatible)
|
||||
- Doctrine ORM: 3.6.0 (compatible)
|
||||
- All 433 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) |
|
||||
|
||||
---
|
||||
|
||||
## Current State Analysis
|
||||
|
||||
### PHP Version Compatibility
|
||||
|
||||
- **Current Runtime:** PHP 8.3.30
|
||||
- **Composer Platform:** PHP 8.3.30
|
||||
- **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 |
|
||||
| `league/flysystem-bundle` | 3.6.1 | Yes |
|
||||
| `league/flysystem-sftp-v3` | 3.30.0 | Yes |
|
||||
| `nelexa/zip` | 4.0.2 | Yes (verify post-upgrade) |
|
||||
| `spatie/crypto` | 2.1.1 | Yes |
|
||||
| `easycorp/easyadmin-bundle` | 4.29.1 (^4.27) | 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 433 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/maker-bundle": "^1.0",
|
||||
"symfony/phpunit-bridge": "7.4.*",
|
||||
"symfony/stopwatch": "7.4.*",
|
||||
"symfony/web-profiler-bundle": "7.4.*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Keep `symfony/maker-bundle` at `^1.0` (compatible with Symfony 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.*"`
|
||||
- Consider tightening `php` to `>=8.2` (Symfony 7.4 requires 8.2+; optional if already on 8.3)
|
||||
|
||||
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
|
||||
- [ ] EasyAdmin CRUD / admin panels
|
||||
|
||||
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
|
||||
|
||||
6. **Verify ZIP File Functionality**
|
||||
- Test any features using `nelexa/zip` (package last updated 2022)
|
||||
- Verify document generation and downloads work correctly
|
||||
|
||||
### 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 (433 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 (433 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:** 7.0
|
||||
**Previous Version:** 6.0 (dated 2026-01-09)
|
||||
**Last Updated:** 2026-02-23
|
||||
**Status:** Ready for Symfony 7.4 Upgrade (updated for current project state)
|
||||
File diff suppressed because it is too large.
Load diff
+68
-6
@@ -30,6 +30,59 @@
|
||||
"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",
|
||||
"Scope": "api"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,8 +95,8 @@
|
||||
"Grant Type": "Authorization Code",
|
||||
"Client ID": "{{oauth2_client_id}}",
|
||||
"Client Secret": "{{oauth2_client_secret}}",
|
||||
"Auth URL": "https://myep.ep-reisen.de/authorize",
|
||||
"Token URL": "https://myep.ep-reisen.de/token",
|
||||
"Auth URL": "https://my.ep-reisen.de/authorize",
|
||||
"Token URL": "https://my.ep-reisen.de/token",
|
||||
"Redirect URL": "https://myep-team.ep-reisen.de/auth/check",
|
||||
"Scope": "email"
|
||||
},
|
||||
@@ -52,8 +105,8 @@
|
||||
"Grant Type": "Authorization Code",
|
||||
"Client ID": "{{oauth2_client_id}}",
|
||||
"Client Secret": "{{oauth2_client_secret}}",
|
||||
"Auth URL": "https://myep.ep-reisen.de/authorize",
|
||||
"Token URL": "https://myep.ep-reisen.de/token",
|
||||
"Auth URL": "https://my.ep-reisen.de/authorize",
|
||||
"Token URL": "https://my.ep-reisen.de/token",
|
||||
"Redirect URL": "https://myep-team.ep-reisen.de/auth/check",
|
||||
"Scope": "email profile"
|
||||
},
|
||||
@@ -62,8 +115,17 @@
|
||||
"Grant Type": "Client Credentials",
|
||||
"Client ID": "{{oauth2_api_client_id}}",
|
||||
"Client Secret": "{{oauth2_api_client_secret}}",
|
||||
"Auth URL": "https://myep.ep-reisen.de/authorize",
|
||||
"Token URL": "https://myep.ep-reisen.de/token",
|
||||
"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",
|
||||
"Scope": "api"
|
||||
}
|
||||
}
|
||||
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
###
|
||||
# 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}}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?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`');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?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)');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?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 Version20260702084714 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Replace override price fields with a PriceType column; migrate existing override rows to sibling DISCOUNT records';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_price ADD type VARCHAR(20) DEFAULT NULL');
|
||||
|
||||
$this->addSql(<<<'SQL'
|
||||
INSERT INTO accommodation_price
|
||||
(accommodation_id, date_from, date_to, season, included_pax, min_nights,
|
||||
price_per_night, price_additional_person, accept_undersubscription, type,
|
||||
created_at, updated_at, created_by_id, updated_by_id)
|
||||
SELECT accommodation_id, date_from, date_to, season, included_pax, min_nights,
|
||||
price_per_night_override, price_additional_person_override, accept_undersubscription, 'discount',
|
||||
created_at, updated_at, created_by_id, updated_by_id
|
||||
FROM accommodation_price
|
||||
WHERE price_per_night_override IS NOT NULL
|
||||
SQL);
|
||||
|
||||
$this->addSql('ALTER TABLE accommodation_price DROP price_per_night_override, DROP price_additional_person_override');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_price ADD price_per_night_override INT DEFAULT NULL, ADD price_additional_person_override INT DEFAULT NULL, DROP type');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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 Version20260706120805 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 DROP min_pax_summer');
|
||||
$this->addSql('ALTER TABLE accommodation_price ADD accept_short_term 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 ADD min_pax_summer INT NOT NULL');
|
||||
$this->addSql('ALTER TABLE accommodation_price DROP accept_short_term');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?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 Version20260706141648 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add accommodation_inquiry and accommodation_inquiry_additional_service tables';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE accommodation_booking (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)\', pax_count INT NOT NULL, minors_count INT NOT NULL, children_count INT NOT NULL, adolescents_count INT NOT NULL, board_service_label VARCHAR(255) DEFAULT NULL, board_service_price INT DEFAULT NULL, board_service_original_id INT DEFAULT NULL, is_inquiry TINYINT(1) NOT NULL, salutation VARCHAR(10) DEFAULT NULL, first_name VARCHAR(100) NOT NULL, last_name VARCHAR(100) NOT NULL, email VARCHAR(255) NOT NULL, phone VARCHAR(50) DEFAULT NULL, street VARCHAR(255) DEFAULT NULL, zip VARCHAR(20) DEFAULT NULL, city VARCHAR(100) DEFAULT NULL, country VARCHAR(5) DEFAULT NULL, remarks LONGTEXT DEFAULT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_160D770A8F3692CD (accommodation_id), INDEX IDX_160D770AB03A8386 (created_by_id), INDEX IDX_160D770A896DBBDE (updated_by_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||
$this->addSql('CREATE TABLE accommodation_inquiry_additional_service (id INT AUTO_INCREMENT NOT NULL, inquiry_id INT NOT NULL, label VARCHAR(255) NOT NULL, price INT NOT NULL, type VARCHAR(20) NOT NULL, original_service_id INT DEFAULT NULL, INDEX IDX_B28A7FD8A7AD6D71 (inquiry_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||
$this->addSql('ALTER TABLE accommodation_booking ADD CONSTRAINT FK_160D770A8F3692CD FOREIGN KEY (accommodation_id) REFERENCES accommodation (id)');
|
||||
$this->addSql('ALTER TABLE accommodation_booking ADD CONSTRAINT FK_160D770AB03A8386 FOREIGN KEY (created_by_id) REFERENCES user (id) ON DELETE SET NULL');
|
||||
$this->addSql('ALTER TABLE accommodation_booking ADD CONSTRAINT FK_160D770A896DBBDE FOREIGN KEY (updated_by_id) REFERENCES user (id) ON DELETE SET NULL');
|
||||
$this->addSql('ALTER TABLE accommodation_inquiry_additional_service ADD CONSTRAINT FK_B28A7FD8A7AD6D71 FOREIGN KEY (inquiry_id) REFERENCES accommodation_booking (id)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP FOREIGN KEY FK_160D770A8F3692CD');
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP FOREIGN KEY FK_160D770AB03A8386');
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP FOREIGN KEY FK_160D770A896DBBDE');
|
||||
$this->addSql('ALTER TABLE accommodation_inquiry_additional_service DROP FOREIGN KEY FK_B28A7FD8A7AD6D71');
|
||||
$this->addSql('DROP TABLE accommodation_booking');
|
||||
$this->addSql('DROP TABLE accommodation_inquiry_additional_service');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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 Version20260707094812 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Drop children_count (4–5 J.) and rename adolescents_count to children_count (now 4–X J.)';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP COLUMN children_count');
|
||||
$this->addSql('ALTER TABLE accommodation_booking RENAME COLUMN adolescents_count TO children_count');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking RENAME COLUMN children_count TO adolescents_count');
|
||||
$this->addSql('ALTER TABLE accommodation_booking ADD COLUMN children_count INT NOT NULL DEFAULT 0');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20260707150000 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add group_name to accommodation_inquiry';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql("ALTER TABLE accommodation_booking ADD COLUMN group_name VARCHAR(255) NOT NULL DEFAULT ''");
|
||||
$this->addSql("ALTER TABLE accommodation_booking ALTER COLUMN group_name DROP DEFAULT");
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP COLUMN group_name');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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 Version20260708071724 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Replace accommodation_inquiry_additional_service table with JSON column; add uuid unique index';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE accommodation_inquiry_additional_service DROP FOREIGN KEY FK_B28A7FD8A7AD6D71');
|
||||
$this->addSql('DROP TABLE accommodation_inquiry_additional_service');
|
||||
$this->addSql('ALTER TABLE accommodation_booking ADD additional_services JSON NOT NULL');
|
||||
$this->addSql('ALTER TABLE accommodation_booking ADD uuid VARCHAR(36) DEFAULT NULL');
|
||||
$this->addSql('UPDATE accommodation_booking SET uuid = UUID()');
|
||||
$this->addSql('ALTER TABLE accommodation_booking MODIFY uuid VARCHAR(36) NOT NULL');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_160D770AD17F50A6 ON accommodation_booking (uuid)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE accommodation_inquiry_additional_service (id INT AUTO_INCREMENT NOT NULL, inquiry_id INT NOT NULL, label VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, price INT NOT NULL, type VARCHAR(20) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, original_service_id INT DEFAULT NULL, INDEX IDX_B28A7FD8A7AD6D71 (inquiry_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
|
||||
$this->addSql('ALTER TABLE accommodation_inquiry_additional_service ADD CONSTRAINT FK_B28A7FD8A7AD6D71 FOREIGN KEY (inquiry_id) REFERENCES accommodation_booking (id) ON UPDATE NO ACTION ON DELETE NO ACTION');
|
||||
$this->addSql('DROP INDEX UNIQ_160D770AD17F50A6 ON accommodation_booking');
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP additional_services, DROP uuid');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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 Version20260708081559 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 description LONGTEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE board_service ADD description LONGTEXT DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE additional_service DROP description');
|
||||
$this->addSql('ALTER TABLE board_service DROP description');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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 Version20260708102807 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_booking ADD discount 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_booking DROP discount');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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 Version20260709133922 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Drop manual sorting column from board_service/additional_service; they are now ordered by dateFrom then label.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE additional_service DROP sorting');
|
||||
$this->addSql('ALTER TABLE board_service DROP sorting');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE additional_service ADD sorting INT NOT NULL');
|
||||
$this->addSql('ALTER TABLE board_service ADD sorting INT NOT NULL');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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 Version20260709141929 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add nullable accepted_at column to accommodation_booking for audit tracking of inquiry-to-booking acceptance.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE
|
||||
accommodation_booking
|
||||
ADD
|
||||
accepted_at DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)'
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP accepted_at');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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 Version20260709162705 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add nullable access_link_issued_at column to accommodation_booking for the customer-facing offer/accept access link.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql(<<<'SQL'
|
||||
ALTER TABLE
|
||||
accommodation_booking
|
||||
ADD
|
||||
access_link_issued_at DATETIME DEFAULT NULL COMMENT '(DC2Type:datetime_immutable)'
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP access_link_issued_at');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20260710130000 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Store an authoritative price snapshot on accommodation bookings';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking ADD price_breakdown JSON DEFAULT NULL, ADD total_price INT DEFAULT NULL, ADD pricing_currency VARCHAR(3) DEFAULT NULL, ADD pricing_version SMALLINT DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP price_breakdown, DROP total_price, DROP pricing_currency, DROP pricing_version');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20260716101949 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Split the single accommodation booking discount into per-component discounts';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking CHANGE discount accommodation_discount INT DEFAULT NULL, ADD board_service_discount INT DEFAULT NULL, ADD additional_services_discount INT DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking CHANGE accommodation_discount discount INT DEFAULT NULL, DROP board_service_discount, DROP additional_services_discount');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?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 Version20260717103431 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_booking ADD managed_by_id INT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE accommodation_booking ADD CONSTRAINT FK_AC389924873649CA FOREIGN KEY (managed_by_id) REFERENCES user (id) ON DELETE SET NULL');
|
||||
$this->addSql('CREATE INDEX IDX_AC389924873649CA ON accommodation_booking (managed_by_id)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP FOREIGN KEY FK_AC389924873649CA');
|
||||
$this->addSql('DROP INDEX IDX_AC389924873649CA ON accommodation_booking');
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP managed_by_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20260804120000 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add exclusion group and exclusive flag to additional services';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// The default only backfills existing rows; it is dropped again so the column matches the mapping.
|
||||
$this->addSql('ALTER TABLE additional_service ADD exclusion_group VARCHAR(128) DEFAULT NULL, ADD is_exclusive TINYINT(1) DEFAULT 0 NOT NULL');
|
||||
$this->addSql('ALTER TABLE additional_service ALTER COLUMN is_exclusive DROP DEFAULT');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE additional_service DROP exclusion_group, DROP is_exclusive');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20260804140000 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add manual ordering position to additional services';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// The default only backfills existing rows; it is dropped again so the column matches the mapping.
|
||||
$this->addSql('ALTER TABLE additional_service ADD position INT DEFAULT 0 NOT NULL');
|
||||
$this->addSql('ALTER TABLE additional_service ALTER COLUMN position DROP DEFAULT');
|
||||
|
||||
// Seed the positions with the ordering the admin overview used before, so nothing changes
|
||||
// visually until someone actually drags a row.
|
||||
$this->addSql('
|
||||
UPDATE additional_service s
|
||||
JOIN (
|
||||
SELECT id, ROW_NUMBER() OVER (
|
||||
PARTITION BY accommodation_id
|
||||
ORDER BY date_from ASC, (price <> 0) ASC, label ASC
|
||||
) AS rn
|
||||
FROM additional_service
|
||||
) o ON o.id = s.id
|
||||
SET s.position = o.rn
|
||||
');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE additional_service DROP position');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?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 Version20260804152215 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Make accommodation booking contact fields nullable (filled on the edit page after creation)';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking CHANGE first_name first_name VARCHAR(100) DEFAULT NULL, CHANGE last_name last_name VARCHAR(100) DEFAULT NULL, CHANGE email email VARCHAR(255) DEFAULT NULL, CHANGE group_name group_name VARCHAR(255) DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking CHANGE group_name group_name VARCHAR(255) NOT NULL, CHANGE first_name first_name VARCHAR(100) NOT NULL, CHANGE last_name last_name VARCHAR(100) NOT NULL, CHANGE email email VARCHAR(255) NOT NULL');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?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 Version20260804153855 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Replace the accommodation booking is_inquiry flag with a four-value status';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking ADD status VARCHAR(20) DEFAULT NULL');
|
||||
$this->addSql("UPDATE accommodation_booking SET status = IF(is_inquiry = 1, 'inquiry', 'booking')");
|
||||
$this->addSql('ALTER TABLE accommodation_booking CHANGE status status VARCHAR(20) NOT NULL');
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP is_inquiry');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking ADD is_inquiry TINYINT(1) DEFAULT NULL');
|
||||
$this->addSql("UPDATE accommodation_booking SET is_inquiry = IF(status = 'inquiry', 1, 0)");
|
||||
$this->addSql('ALTER TABLE accommodation_booking CHANGE is_inquiry is_inquiry TINYINT(1) NOT NULL');
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP status');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20260805102251 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add country to accommodation, defaulting existing rows to DE';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// Added with a default so existing rows backfill to DE, then dropped again to match the mapping
|
||||
$this->addSql("ALTER TABLE accommodation ADD country VARCHAR(2) DEFAULT 'DE' NOT NULL");
|
||||
$this->addSql('ALTER TABLE accommodation ALTER country DROP DEFAULT');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation DROP country');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20260806120000 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Split the accommodation booking status into a status and a type';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE accommodation_booking ADD type VARCHAR(20) DEFAULT NULL');
|
||||
|
||||
// An old 'booking' row with an accepted_at came from an accepted offer, so it is an
|
||||
// Anfrage; without one it was placed directly. Rows in 'draft'/'discarded' carry no
|
||||
// trace of their kind any more — they are mapped to 'inquiry', which is where the
|
||||
// office path produces them.
|
||||
$this->addSql("UPDATE accommodation_booking SET type = CASE
|
||||
WHEN status = 'booking' AND accepted_at IS NULL THEN 'booking'
|
||||
ELSE 'inquiry' END");
|
||||
|
||||
$this->addSql("UPDATE accommodation_booking SET status = CASE
|
||||
WHEN status = 'inquiry' THEN 'open'
|
||||
WHEN status = 'booking' THEN 'accepted'
|
||||
ELSE status END");
|
||||
|
||||
$this->addSql('ALTER TABLE accommodation_booking CHANGE type type VARCHAR(20) NOT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql("UPDATE accommodation_booking SET status = CASE
|
||||
WHEN status IN ('draft', 'discarded') THEN status
|
||||
WHEN type = 'inquiry' AND status = 'open' THEN 'inquiry'
|
||||
ELSE 'booking' END");
|
||||
|
||||
$this->addSql('ALTER TABLE accommodation_booking DROP type');
|
||||
}
|
||||
}
|
||||
Generated
+1646
-1979
File diff suppressed because it is too large.
Load diff
+9
-3
@@ -5,7 +5,7 @@
|
||||
"@babel/preset-env": "^7.16.0",
|
||||
"@hotwired/stimulus": "^3.0.0",
|
||||
"@symfony/stimulus-bridge": "^3.2.0",
|
||||
"@symfony/webpack-encore": "^5.0.0",
|
||||
"@symfony/webpack-encore": "^6.0.0",
|
||||
"@tailwindcss/forms": "^0.5.9",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"autoprefixer": "^10.4.20",
|
||||
@@ -20,8 +20,7 @@
|
||||
"tippy.js": "^6.3.7",
|
||||
"toastify-js": "^1.12.0",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^5.1.0",
|
||||
"webpack-notifier": "^1.15.0"
|
||||
"webpack-cli": "^6.0.1"
|
||||
},
|
||||
"license": "WTFPL",
|
||||
"private": true,
|
||||
@@ -31,5 +30,12 @@
|
||||
"watch": "encore dev --watch",
|
||||
"build": "encore production --progress",
|
||||
"cy:open": "cypress open"
|
||||
},
|
||||
"dependencies": {
|
||||
"@trevoreyre/autocomplete-js": "^3.0.3",
|
||||
"glightbox": "^3.3.1",
|
||||
"sortablejs": "^1.15.7",
|
||||
"stimulus-use": "^0.52.3",
|
||||
"vanilla-calendar-pro": "^3.1.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
includes:
|
||||
- vendor/phpstan/phpstan-symfony/extension.neon
|
||||
- vendor/phpstan/phpstan-doctrine/extension.neon
|
||||
|
||||
parameters:
|
||||
level: 6
|
||||
paths:
|
||||
- src
|
||||
tmpDir: var/phpstan
|
||||
parallel:
|
||||
maximumNumberOfProcesses: 1
|
||||
symfony:
|
||||
containerXmlPath: var/cache/dev/App_KernelDevDebugContainer.xml
|
||||
doctrine:
|
||||
objectManagerLoader: tests/doctrine-object-manager.php
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Config\RectorConfig;
|
||||
|
||||
return RectorConfig::configure()
|
||||
->withPaths([
|
||||
__DIR__.'/src',
|
||||
__DIR__.'/tests',
|
||||
])
|
||||
->withImportNames(
|
||||
importShortClasses: false,
|
||||
removeUnusedImports: true,
|
||||
)
|
||||
->withComposerBased(
|
||||
doctrine: true,
|
||||
symfony: true,
|
||||
)
|
||||
->withSymfonyContainerXml(
|
||||
__DIR__.'/var/cache/dev/App_KernelDevDebugContainer.xml'
|
||||
)
|
||||
->withFluentCallNewLine()
|
||||
->withCache(__DIR__.'/var/rector');
|
||||
Loaded 100 of 728 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user