| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,25 @@ |
| 1 |
+<?php |
|
| 2 |
+ |
|
| 3 |
+/* |
|
| 4 |
+ * This file is part of contao-weinanlieferung-bundle. |
|
| 5 |
+ * |
|
| 6 |
+ * (c) vonRotenberg |
|
| 7 |
+ * |
|
| 8 |
+ * @license commercial |
|
| 9 |
+ */ |
|
| 10 |
+ |
|
| 11 |
+use Contao\CoreBundle\DataContainer\PaletteManipulator; |
|
| 12 |
+ |
|
| 13 |
+PaletteManipulator::create() |
|
| 14 |
+ ->addLegend('wa_config_legend','global_legend')
|
|
| 15 |
+ ->addField('vr_wa_uploadFolderSRC','wa_config_legend',PaletteManipulator::POSITION_APPEND)
|
|
| 16 |
+ ->applyToPalette('root','tl_page')
|
|
| 17 |
+ ->applyToPalette('rootfallback','tl_page');
|
|
| 18 |
+ |
|
| 19 |
+ |
|
| 20 |
+$GLOBALS['TL_DCA']['tl_page']['fields']['vr_wa_uploadFolderSRC'] = array( |
|
| 21 |
+ 'exclude' => true, |
|
| 22 |
+ 'inputType' => 'fileTree', |
|
| 23 |
+ 'eval' => array('fieldType'=>'radio', 'files'=>false, 'mandatory'=>true, 'tl_class'=>'clr'),
|
|
| 24 |
+ 'sql' => "binary(16) NULL" |
|
| 25 |
+); |
| ... | ... |
@@ -10,6 +10,7 @@ |
| 10 | 10 |
|
| 11 | 11 |
use Contao\DC_Table; |
| 12 | 12 |
use Contao\DataContainer; |
| 13 |
+use Contao\Config; |
|
| 13 | 14 |
|
| 14 | 15 |
$GLOBALS['TL_DCA']['tl_vr_wa_reservation'] = array |
| 15 | 16 |
( |
| ... | ... |
@@ -39,6 +40,12 @@ $GLOBALS['TL_DCA']['tl_vr_wa_reservation'] = array |
| 39 | 40 |
'sql' => "int(10) unsigned NOT NULL default '0'", |
| 40 | 41 |
'relation' => array('type' => 'belongsTo', 'load' => 'lazy')
|
| 41 | 42 |
), |
| 43 |
+ 'rootid' => array |
|
| 44 |
+ ( |
|
| 45 |
+ 'foreignKey' => 'tl_page.title', |
|
| 46 |
+ 'sql' => "int(10) unsigned NOT NULL default '0'", |
|
| 47 |
+ 'relation' => array('type' => 'belongsTo', 'load' => 'lazy')
|
|
| 48 |
+ ), |
|
| 42 | 49 |
'tstamp' => array |
| 43 | 50 |
( |
| 44 | 51 |
'sql' => "int(10) unsigned NOT NULL default '0'" |
| ... | ... |
@@ -60,5 +67,23 @@ $GLOBALS['TL_DCA']['tl_vr_wa_reservation'] = array |
| 60 | 67 |
'sql' => "blob NULL", |
| 61 | 68 |
'relation' => array('type' => 'hasMany', 'load' => 'lazy')
|
| 62 | 69 |
), |
| 70 |
+ 'upload' => array |
|
| 71 |
+ ( |
|
| 72 |
+ 'exclude' => true, |
|
| 73 |
+ 'inputType' => 'fileTree', |
|
| 74 |
+ 'eval' => array('filesOnly'=>true, 'fieldType'=>'radio', 'tl_class'=>'clr', 'extensions'=>Config::get('allowedDownload')),
|
|
| 75 |
+ 'sql' => "binary(16) NULL" |
|
| 76 |
+ ), |
|
| 77 |
+ 'filename' => array |
|
| 78 |
+ ( |
|
| 79 |
+ 'exclude' => true, |
|
| 80 |
+ 'inputType' => 'text', |
|
| 81 |
+ 'eval' => array |
|
| 82 |
+ ( |
|
| 83 |
+ 'maxlength' => 255, |
|
| 84 |
+ 'decodeEntities'=>true |
|
| 85 |
+ ), |
|
| 86 |
+ 'sql' => "varchar(255) BINARY NOT NULL default ''" |
|
| 87 |
+ ), |
|
| 63 | 88 |
) |
| 64 | 89 |
); |
| 17 | 19 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,14 @@ |
| 1 |
+<?php |
|
| 2 |
+ |
|
| 3 |
+/** |
|
| 4 |
+ * This file is part of contao-weinanlieferung-bundle. |
|
| 5 |
+ * |
|
| 6 |
+ * (c) vonRotenberg |
|
| 7 |
+ * |
|
| 8 |
+ * @license commercial |
|
| 9 |
+ */ |
|
| 10 |
+ |
|
| 11 |
+$GLOBALS['TL_LANG']['tl_page']['vr_wa_uploadFolderSRC'][0] = 'Upload-Ordner'; |
|
| 12 |
+$GLOBALS['TL_LANG']['tl_page']['vr_wa_uploadFolderSRC'][1] = 'Hier werden die hochgeladenen Dateien abgelegt.'; |
|
| 13 |
+ |
|
| 14 |
+$GLOBALS['TL_LANG']['tl_page']['wa_config_legend'] = 'Weinanlieferung-Einstellungen'; |
| 0 | 15 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,12 @@ |
| 1 |
+<?php |
|
| 2 |
+ |
|
| 3 |
+/** |
|
| 4 |
+ * This file is part of contao-weinanlieferung-bundle. |
|
| 5 |
+ * |
|
| 6 |
+ * (c) vonRotenberg |
|
| 7 |
+ * |
|
| 8 |
+ * @license commercial |
|
| 9 |
+ */ |
|
| 10 |
+ |
|
| 11 |
+$GLOBALS['TL_LANG']['MSC']['wa_sorte'] = 'Grape variety'; |
|
| 12 |
+$GLOBALS['TL_LANG']['MSC']['wa_leseart'] = 'Harvest type'; |
| ... | ... |
@@ -59,8 +59,11 @@ |
| 59 | 59 |
|
| 60 | 60 |
<div class="frame__body"> |
| 61 | 61 |
<h4>Reservieren</h4> |
| 62 |
+ {% if toast is defined %}
|
|
| 63 |
+ {{ toast|raw }}
|
|
| 64 |
+ {% endif %}
|
|
| 62 | 65 |
{% if buchen.buchbar %}
|
| 63 |
- <form hx-post="/_ajax/vr_wa/v1/slot?do=reservate"> |
|
| 66 |
+ <form hx-post="/_ajax/vr_wa/v1/slot?do=reservate" enctype="multipart/form-data"> |
|
| 64 | 67 |
<input type="hidden" name="id" value="{{ id }}">
|
| 65 | 68 |
<fieldset> |
| 66 | 69 |
<label for="res-behaelter">Liefernde Behältermenge</label> |
| ... | ... |
@@ -78,6 +81,10 @@ |
| 78 | 81 |
{% endfor %}
|
| 79 | 82 |
</fieldset> |
| 80 | 83 |
<fieldset> |
| 84 |
+ <label for="res-upload">Dateianhang</label> |
|
| 85 |
+ <input type="file" id="res-upload" name="upload"> |
|
| 86 |
+ </fieldset> |
|
| 87 |
+ <fieldset> |
|
| 81 | 88 |
<button type="submit">Reservieren</button> |
| 82 | 89 |
</fieldset> |
| 83 | 90 |
</form> |
| ... | ... |
@@ -31,6 +31,16 @@ |
| 31 | 31 |
</div> |
| 32 | 32 |
{% endfor %}
|
| 33 | 33 |
</div> |
| 34 |
+ {% else %}
|
|
| 35 |
+ <div class="placeholder"> |
|
| 36 |
+ <h6 class="placeholder-title">Sie haben noch keine Anlieferungszeiten reserviert</h6> |
|
| 37 |
+ <div class="placeholder-subtitle">Sobald Sie Anlieferungszeiten reserviert haben, werden diese hier aufgelistet.</div> |
|
| 38 |
+ <div class="placeholder-commands u-center"> |
|
| 39 |
+ <div class="m-1"> |
|
| 40 |
+ <a href="{{ insert_tag('link_url::2') }}" class="btn btn-info">Zur Reservierung</a>
|
|
| 41 |
+ </div> |
|
| 42 |
+ </div> |
|
| 43 |
+ </div> |
|
| 34 | 44 |
{% endif %}
|
| 35 | 45 |
{% endblock %}
|
| 36 | 46 |
|
| ... | ... |
@@ -1,35 +1,37 @@ |
| 1 | 1 |
<div hx-get="{{ insert_tag('env::request') }}" hx-headers='{"VR-Ajax": "WaSlotsModule"}' hx-trigger="updateWaList from:body, updateWaBooking from:body" class="{{ class }} content-wrapper block"{{ cssID }}{% if style is defined and style is not empty %} style="{{ style }}"{% endif %}>
|
| 2 | 2 |
|
| 3 | 3 |
{% block filter %}
|
| 4 |
- <form hx-get="{{ insert_tag('env::request') }}" hx-push-url="true" hx-headers='{"VR-Ajax": "WaSlotsModule"}' hx-trigger="change, submit" hx-target="closest .content-wrapper" class="filter">
|
|
| 5 |
- <div class="row"> |
|
| 6 |
- <div class="col-md-3 kapazitaet"> |
|
| 7 |
- <select name="filter_kapazitaet"> |
|
| 8 |
- <option value="">-</option> |
|
| 9 |
- {% for option in filter.kapazitaet.options %}
|
|
| 10 |
- <option value="{{ option }}"{% if filter.kapazitaet.selected is defined and filter.kapazitaet.selected == option %} selected{% endif %}>{{ option }}</option>
|
|
| 11 |
- {% endfor %}
|
|
| 12 |
- </select> |
|
| 13 |
- </div> |
|
| 14 |
- <div class="col-md-3 sorte"> |
|
| 15 |
- <select name="filter_sorte"> |
|
| 16 |
- <option value="">-</option> |
|
| 17 |
- {% for key, option in filter.sorte.options %}
|
|
| 18 |
- <option value="{{ key }}"{% if filter.sorte.selected is defined and filter.sorte.selected == key %} selected{% endif %}>{{ option }}</option>
|
|
| 19 |
- {% endfor %}
|
|
| 20 |
- </select> |
|
| 21 |
- </div> |
|
| 22 |
- <div class="col-md-3 leseart"> |
|
| 23 |
- <select name="filter_leseart"> |
|
| 24 |
- <option value="">-</option> |
|
| 25 |
- {% for key, option in filter.leseart.options %}
|
|
| 26 |
- <option value="{{ key }}"{% if filter.leseart.selected is defined and filter.leseart.selected == key %} selected{% endif %}>{{ option }}</option>
|
|
| 27 |
- {% endfor %}
|
|
| 28 |
- </select> |
|
| 4 |
+ {% if days is defined and days|length %}
|
|
| 5 |
+ <form hx-get="{{ insert_tag('env::request') }}" hx-push-url="true" hx-headers='{"VR-Ajax": "WaSlotsModule"}' hx-trigger="change, submit" hx-target="closest .content-wrapper" class="filter">
|
|
| 6 |
+ <div class="row"> |
|
| 7 |
+ <div class="col-md-3 kapazitaet"> |
|
| 8 |
+ <select name="filter_kapazitaet"> |
|
| 9 |
+ <option value="">-</option> |
|
| 10 |
+ {% for option in filter.kapazitaet.options %}
|
|
| 11 |
+ <option value="{{ option }}"{% if filter.kapazitaet.selected is defined and filter.kapazitaet.selected == option %} selected{% endif %}>{{ option }}</option>
|
|
| 12 |
+ {% endfor %}
|
|
| 13 |
+ </select> |
|
| 14 |
+ </div> |
|
| 15 |
+ <div class="col-md-3 sorte"> |
|
| 16 |
+ <select name="filter_sorte"> |
|
| 17 |
+ <option value="">-</option> |
|
| 18 |
+ {% for key, option in filter.sorte.options %}
|
|
| 19 |
+ <option value="{{ key }}"{% if filter.sorte.selected is defined and filter.sorte.selected == key %} selected{% endif %}>{{ option }}</option>
|
|
| 20 |
+ {% endfor %}
|
|
| 21 |
+ </select> |
|
| 22 |
+ </div> |
|
| 23 |
+ <div class="col-md-3 leseart"> |
|
| 24 |
+ <select name="filter_leseart"> |
|
| 25 |
+ <option value="">-</option> |
|
| 26 |
+ {% for key, option in filter.leseart.options %}
|
|
| 27 |
+ <option value="{{ key }}"{% if filter.leseart.selected is defined and filter.leseart.selected == key %} selected{% endif %}>{{ option }}</option>
|
|
| 28 |
+ {% endfor %}
|
|
| 29 |
+ </select> |
|
| 30 |
+ </div> |
|
| 31 |
+ <div class="col submit"><button class="u-block w-100p">Filter übernehmen</button></div> |
|
| 29 | 32 |
</div> |
| 30 |
- <div class="col submit"><button class="u-block w-100p">Filter übernehmen</button></div> |
|
| 31 |
- </div> |
|
| 32 |
- </form> |
|
| 33 |
+ </form> |
|
| 34 |
+ {% endif %}
|
|
| 33 | 35 |
{% endblock %}
|
| 34 | 36 |
|
| 35 | 37 |
{% block content %}
|
| ... | ... |
@@ -62,6 +64,11 @@ |
| 62 | 64 |
</div> |
| 63 | 65 |
{% endfor %}
|
| 64 | 66 |
</div> |
| 67 |
+ {% else %}
|
|
| 68 |
+ <div class="placeholder"> |
|
| 69 |
+ <h6 class="placeholder-title">Derzeit sind keine buchbaren Anlieferungszeiten verfügbar</h6> |
|
| 70 |
+ <div class="placeholder-subtitle">Sie können uns auch gerne anrufen.</div> |
|
| 71 |
+ </div> |
|
| 65 | 72 |
{% endif %}
|
| 66 | 73 |
{% endblock %}
|
| 67 | 74 |
|
| ... | ... |
@@ -16,6 +16,8 @@ use Contao\Controller; |
| 16 | 16 |
use Contao\CoreBundle\Controller\AbstractController; |
| 17 | 17 |
use Contao\CoreBundle\Framework\ContaoFramework; |
| 18 | 18 |
use Contao\CoreBundle\Security\Authentication\Token\TokenChecker; |
| 19 |
+use Contao\FormFileUpload; |
|
| 20 |
+use Contao\Frontend; |
|
| 19 | 21 |
use Contao\FrontendUser; |
| 20 | 22 |
use Contao\Input; |
| 21 | 23 |
use Contao\StringUtil; |
| ... | ... |
@@ -88,7 +90,7 @@ class SlotAjaxController extends AbstractController |
| 88 | 90 |
return new Response('',500);
|
| 89 | 91 |
} |
| 90 | 92 |
|
| 91 |
- protected function renderDetails(bool $blnModal=true) |
|
| 93 |
+ protected function renderDetails(bool $blnModal=true,string $error=null) |
|
| 92 | 94 |
{
|
| 93 | 95 |
if (empty($_REQUEST['id'])) |
| 94 | 96 |
{
|
| ... | ... |
@@ -158,6 +160,11 @@ class SlotAjaxController extends AbstractController |
| 158 | 160 |
'reservations' => $arrReservations |
| 159 | 161 |
]; |
| 160 | 162 |
|
| 163 |
+ if (!empty($error)) |
|
| 164 |
+ {
|
|
| 165 |
+ $arrData['toast'] = $error; |
|
| 166 |
+ } |
|
| 167 |
+ |
|
| 161 | 168 |
return $this->render('@Contao/modal_slot_details.html.twig',$arrData);
|
| 162 | 169 |
} |
| 163 | 170 |
|
| ... | ... |
@@ -217,6 +224,27 @@ class SlotAjaxController extends AbstractController |
| 217 | 224 |
|
| 218 | 225 |
protected function reservate() |
| 219 | 226 |
{
|
| 227 |
+ Controller::loadDataContainer('tl_vr_wa_reservation');
|
|
| 228 |
+ $arrData = []; |
|
| 229 |
+ |
|
| 230 |
+ if (($rootPage = Frontend::getRootPageFromUrl()) !== null && !empty($rootPage->vr_wa_uploadFolderSRC)) |
|
| 231 |
+ {
|
|
| 232 |
+ $File = new FormFileUpload(\Contao\Widget::getAttributesFromDca($GLOBALS['TL_DCA']['tl_vr_wa_reservation']['fields']['upload'], 'upload')); |
|
| 233 |
+ $File->storeFile = true; |
|
| 234 |
+ $File->doNotOverwrite = true; |
|
| 235 |
+ $File->uploadFolder = $rootPage->vr_wa_uploadFolderSRC; |
|
| 236 |
+ |
|
| 237 |
+ $File->validate(); |
|
| 238 |
+ |
|
| 239 |
+ if ($File->hasErrors()) |
|
| 240 |
+ {
|
|
| 241 |
+ return $this->renderDetails(false,'<div class="toast toast--danger mx-0">' . $File->getErrorAsHTML() . '</div>'); |
|
| 242 |
+ } |
|
| 243 |
+ |
|
| 244 |
+ $arrData['filename'] = $_SESSION['FILES'][$File->name]['name'] ?? ''; |
|
| 245 |
+ $arrData['upload'] = $_SESSION['FILES'][$File->name]['uuid'] ? StringUtil::uuidToBin($_SESSION['FILES'][$File->name]['uuid']) : null; |
|
| 246 |
+ } |
|
| 247 |
+ |
|
| 220 | 248 |
if (empty($_REQUEST['id']) || empty(Input::post('behaelter')) || empty(Input::post('sorten')))
|
| 221 | 249 |
{
|
| 222 | 250 |
return new Response('Missing parameter',412);
|
| ... | ... |
@@ -231,14 +259,15 @@ class SlotAjaxController extends AbstractController |
| 231 | 259 |
} |
| 232 | 260 |
|
| 233 | 261 |
$Reservation = new WeinanlieferungReservationModel(); |
| 234 |
- |
|
| 235 |
- $Reservation->setRow([ |
|
| 262 |
+ $arrData = array_merge($arrData,[ |
|
| 236 | 263 |
'pid' => $_REQUEST['id'], |
| 264 |
+ 'rootid' => $rootPage !== null ? $rootPage->id : '', |
|
| 237 | 265 |
'tstamp' => time(), |
| 238 | 266 |
'uid' => FrontendUser::getInstance()->id, |
| 239 | 267 |
'behaelter' => Input::post('behaelter'),
|
| 240 | 268 |
'sorten' => $arrSorten |
| 241 | 269 |
]); |
| 270 |
+ $Reservation->setRow($arrData); |
|
| 242 | 271 |
|
| 243 | 272 |
|
| 244 | 273 |
$Reservation->save(); |