Skip to content

Commit 512885a

Browse files
authored
Merge pull request #18 from sadekd/exceptions
V2
2 parents e23cd6f + e890b9f commit 512885a

38 files changed

+689
-170
lines changed

LICENCE.md renamed to LICENSE.md

File renamed without changes.

README.md

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
11
# Nova Opening Hours Field
22

3-
Laravel Nova custom field for [Spatie Opening Hours](https://github.com/spatie/opening-hours)
3+
[![Latest Stable Version](https://poser.pugx.org/sadekd/nova-opening-hours-field/v)](https://packagist.org/packages/sadekd/nova-opening-hours-field)
4+
[![Total Downloads](https://poser.pugx.org/sadekd/nova-opening-hours-field/downloads)](https://packagist.org/packages/sadekd/nova-opening-hours-field)
5+
[![License](https://poser.pugx.org/sadekd/nova-opening-hours-field/license)](https://packagist.org/packages/sadekd/nova-opening-hours-field)
6+
[![PHP Version Require](https://poser.pugx.org/sadekd/nova-opening-hours-field/require/php)](https://packagist.org/packages/sadekd/nova-opening-hours-field)
7+
8+
[Laravel](https://laravel.com) [Nova](https://nova.laravel.com) custom field for [Spatie Opening Hours](https://github.com/spatie/opening-hours)
9+
10+
### Index
411

512
![Screenshot Index](screenshot-index.png)
613

14+
### Form
15+
716
![Screenshot Form](screenshot-form.png)
817

18+
### Detail
19+
20+
![Screenshot Detail](screenshot-detail.png)
21+
922
## Installation
1023

11-
You can install the package in to a Laravel app that uses [Nova](https://nova.laravel.com) via composer:
24+
You can install the package in to a [Laravel](https://laravel.com) app that uses [Nova](https://nova.laravel.com) via composer:
1225

1326
```bash
1427
composer require sadekd/nova-opening-hours-field
@@ -19,10 +32,9 @@ composer require sadekd/nova-opening-hours-field
1932
Laravel Migration
2033

2134
```php
22-
$table->json('opening_hours');
35+
$table->json('opening_hours'); // can be ->nullable()
2336
```
2437

25-
2638
Laravel Model
2739

2840
```php
@@ -34,15 +46,25 @@ protected $casts = [
3446
Nova Resource
3547

3648
```php
37-
NovaOpeningHoursField::make('opening_hours'),
49+
NovaOpeningHoursField::make(__('Opening Hours'), 'opening_hours'),
50+
// ->allowExceptions(FALSE) // TRUE by default
51+
// ->allowOverflowMidnight(TRUE) // FALSE by default
52+
// ->useTextInputs(TRUE) // FALSE by default
3853
```
3954

55+
## Known issues
56+
57+
- Lazy validation on time field - losing focus when live(help needed)
58+
- Editing date in exceptions causes row jumping - key from date(help needed)
59+
- Browser time input does not support 24:00
60+
- Browser date input does not support recurring format
61+
4062
## TODO
4163

42-
- [ ] Explode interval input => time fields
43-
- [ ] Validation
44-
- [ ] Localization
45-
- [ ] Exceptions
64+
- [x] Explode interval input => time fields
65+
- [x] Validation
66+
- [x] Localization
67+
- [x] Exceptions
4668
- [ ] Tests
4769

4870
## License

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
],
99
"license": "MIT",
1010
"require": {
11-
"php": "^7.2|^8.0"
11+
"php": "^7.2|^8.0",
12+
"spatie/opening-hours": "^2.0"
1213
},
1314
"autoload": {
1415
"psr-4": {

dist/css/field.css

Lines changed: 0 additions & 1 deletion
This file was deleted.

dist/js/field.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/mix-manifest.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
{
2-
"/js/field.js": "/js/field.js",
3-
"/css/field.css": "/css/field.css"
2+
"/js/field.js": "/js/field.js"
43
}

resources/js/components/DateInput.vue

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<template>
2+
<input
3+
:type="useTextInputs ? 'text' : 'date'"
4+
class="form-control form-input form-input-bordered"
5+
:class="{ 'border-danger': !isValid }"
6+
v-model="date"
7+
:min="getMinDate()"
8+
minlength="7"
9+
maxlength="10"
10+
required
11+
/>
12+
</template>
13+
14+
<script>
15+
import {getTodayDate} from "../src/func";
16+
import {useTextInputsProp} from "../src/props";
17+
18+
export default {
19+
props: {
20+
dateProp: String,
21+
...useTextInputsProp,
22+
},
23+
24+
emits: ['updateDate'],
25+
26+
data: function () {
27+
return {
28+
date: this.dateProp,
29+
}
30+
},
31+
32+
computed: {
33+
isValid: function () {
34+
const re = /([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))/;
35+
// console.log(this.date, re.test(this.date))
36+
return re.test(this.date);
37+
}
38+
},
39+
40+
methods: {
41+
getMinDate() {
42+
return getTodayDate()
43+
},
44+
},
45+
46+
watch: {
47+
date(value) {
48+
this.$emit('updateDate', value)
49+
},
50+
},
51+
}
52+
</script>
53+
54+
<style scoped>
55+
input[type="text"] {
56+
width: 125px;
57+
}
58+
59+
input[type="date"] {
60+
width: 175px;
61+
}
62+
</style>

resources/js/components/DetailField.vue

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<template>
2+
<table class="openingHours exceptionsTable table mt-6 w-full">
3+
<tr>
4+
<th class="text-left font-bold" colspan="2">{{ __('Exceptions') }}</th>
5+
<th v-if="editable">
6+
<button class="btn btn-default btn-primary" @click.prevent="$emit('addException')">+</button>
7+
</th>
8+
</tr>
9+
<tr v-for="exception in exceptions">
10+
<td>
11+
<div v-if="editable">
12+
<date-input
13+
:date-prop="exception.date"
14+
:use-text-inputs="useTextInputs"
15+
@updateDate="$emit('renameException', exception.date, $event)"
16+
/>
17+
</div>
18+
<div v-else>{{ exception.date }}</div>
19+
</td>
20+
<td>
21+
<div v-if="Object.values(exception.intervals).length">
22+
<div v-for="(interval, index) in exception.intervals">
23+
<div v-if="editable">
24+
<interval-input
25+
:interval-prop="interval"
26+
:use-text-inputs="useTextInputs"
27+
@updateInterval="$emit('updateInterval', 'exceptions', exception.date, index, $event)"
28+
@removeInterval="$emit('removeInterval', 'exceptions', exception.date, index)"
29+
/>
30+
</div>
31+
<div v-else>{{ interval }}</div>
32+
</div>
33+
</div>
34+
<div v-else>{{ __('Closed') }}</div>
35+
</td>
36+
<td v-if="editable">
37+
<button class="btn btn-default btn-primary" @click.prevent="$emit('addInterval', 'exceptions', exception.date)">+</button>
38+
<button class="btn btn-default btn-danger" @click.prevent="$emit('removeException', exception.date)">-</button>
39+
</td>
40+
</tr>
41+
</table>
42+
</template>
43+
44+
<script>
45+
import IntervalInput from "./IntervalInput";
46+
import DateInput from "./DateInput";
47+
import {editableProp, exceptionsProp, useTextInputsProp} from "../src/props";
48+
49+
export default {
50+
components: { IntervalInput, DateInput },
51+
52+
props: {
53+
...exceptionsProp,
54+
...editableProp,
55+
...useTextInputsProp,
56+
},
57+
58+
emits: ['updateInterval', 'removeInterval', 'addInterval', 'removeException', 'addException', 'renameException'],
59+
}
60+
</script>

resources/js/components/FormField.vue

Lines changed: 0 additions & 39 deletions
This file was deleted.

resources/js/components/IndexField.vue

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<template>
2+
<div class="interval">
3+
<time-input
4+
:time-prop="from"
5+
:use-text-inputs="useTextInputs"
6+
@updateTime="from = $event"
7+
/>
8+
-
9+
<time-input
10+
:time-prop="to"
11+
:use-text-inputs="useTextInputs"
12+
@updateTime="to = $event"
13+
/>
14+
<button class="btn btn-default btn-danger" @click.prevent="$emit('removeInterval')">-</button>
15+
</div>
16+
</template>
17+
18+
<script>
19+
import {useTextInputsProp} from "../src/props";
20+
import TimeInput from "./TimeInput";
21+
22+
export default {
23+
components: {TimeInput},
24+
25+
props: {
26+
intervalProp: String,
27+
...useTextInputsProp,
28+
},
29+
30+
emits: ['updateInterval', 'removeInterval'],
31+
32+
data: function () {
33+
return {
34+
interval: this.intervalProp,
35+
}
36+
},
37+
38+
computed: {
39+
from: {
40+
get() {
41+
return this.interval.split('-')[0]
42+
},
43+
set(value) {
44+
this.interval = [value, this.to].join('-')
45+
},
46+
},
47+
48+
to: {
49+
get() {
50+
return this.interval.split('-')[1]
51+
},
52+
set(value) {
53+
this.interval = [this.from, value].join('-')
54+
},
55+
},
56+
},
57+
58+
watch: {
59+
interval(value) {
60+
// if (value.length !== 11 || value === this.interval) return
61+
this.$emit('updateInterval', value)
62+
},
63+
},
64+
}
65+
</script>
66+
67+
<style scoped>
68+
.interval {
69+
margin: 10px 0;
70+
}
71+
</style>

0 commit comments

Comments
 (0)