Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion demo/app/Sharp/Utils/Filters/PeriodRequiredFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

namespace App\Sharp\Utils\Filters;

use Code16\Sharp\Filters\DateRange\DateRangePreset;
use Code16\Sharp\Filters\DateRangeRequiredFilter;

class PeriodRequiredFilter extends DateRangeRequiredFilter
{
public function buildFilterConfig(): void
{
$this->configureLabel('Period')->configureShowPresets();
$this->configureLabel('Period')
->configureShowPresets(presets: [
DateRangePreset::make(today()->subDays(3), today(), 'Last 3 days'),
DateRangePreset::thisMonth(),
DateRangePreset::thisYear(),
]);
}

public function defaultValue(): array
Expand Down
33 changes: 33 additions & 0 deletions docs/guide/filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,39 @@ class ProductCreationDateFilter extends DateRangeFilter
}
```

You can also define specific presets with the `DateRangePreset` class :

```php
use Code16\Sharp\Filters\DateRange\DateRangePreset;

class ProductCreationDateFilter extends DateRangeFilter
{
public function buildFilterConfig(): void
{
$this->configureShowPresets(presets: [
DateRangePreset::make(today()->subDays(3), today(), 'Last 3 days'),
DateRangePreset::thisMonth(),
]);
}
}
```

Following methods are available (default presets) :
```php
[
DateRangePreset::today(),
DateRangePreset::yesterday(),
DateRangePreset::last7days(),
DateRangePreset::last30days(),
DateRangePreset::last365days(),
DateRangePreset::thisMonth(),
DateRangePreset::lastMonth(),
DateRangePreset::thisYear(),
DateRangePreset::lastYear(),
]
```


## Autocomplete remote filter

If you want to use a remote filter, you can use the `Code16\Sharp\Filters\AutocompleteRemoteFilter` class. It is very similar to the `Code16\Sharp\Filters\SelectFilter` class, but it uses a remote endpoint to fetch the values.
Expand Down
23 changes: 14 additions & 9 deletions resources/js/filters/components/filters/DateRangeFilter.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { parseDate, CalendarDate } from '@internationalized/date';
import { DateRangeFilterData } from "@/types";
import { DateRangeFilterData, DateRangePresetData } from "@/types";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Button } from "@/components/ui/button";
import { CalendarIcon } from "lucide-vue-next";
Expand All @@ -15,7 +15,7 @@
import { FilterEmits, FilterProps } from "@/filters/types";

const props = defineProps<FilterProps<DateRangeFilterData>>();
const emit = defineEmits<FilterEmits<DateRangeFilterData, { start: string, end: string } | { preset: string } | null>>();
const emit = defineEmits<FilterEmits<DateRangeFilterData>>();

const localValue = ref<{ start: CalendarDate | null, end: CalendarDate | null }>();
const inputs = reactive({ start: '', end: '' });
Expand All @@ -34,14 +34,19 @@
renderKey.value++;
}

function isPresetSelected(preset: DateRangePresetData) {
return preset.start === props.value?.start && preset.end === props.value?.end;
}

function onOpen() {
update();
}

function onPresetSelected(preset: DateRangeFilterData['presets'][number]) {
function onPresetSelect(preset: DateRangePresetData) {
open.value = false;
emit('input', {
preset: preset.key,
start: preset.start,
end: preset.end,
});
}

Expand Down Expand Up @@ -105,7 +110,7 @@
</span>
<template v-if="props.value && 'start' in props.value">
<Separator orientation="vertical" class="h-4" />
<DateRangeFilterValue v-bind="props" />
<DateRangeFilterValue v-bind="props" :preset="props.filter.presets.find(p => isPresetSelected(p))" />
</template>
</Button>
</template>
Expand All @@ -120,7 +125,7 @@
:aria-label="filter.label"
>
<template v-if="props.value && 'start' in props.value">
<DateRangeFilterValue v-bind="props" />
<DateRangeFilterValue v-bind="props" :preset="props.filter.presets.find(p => isPresetSelected(p))" />
</template>
<template v-else>
<span class="text-muted-foreground">
Expand All @@ -137,11 +142,11 @@
<div class="flex flex-col shrink-0 p-3">
<template v-for="preset in filter.presets">
<Button
class="text-left justify-start"
:class="{ 'bg-accent text-accent-foreground': preset.key === props.value?.preset }"
class="text-left justify-start aria-current:bg-accent aria-current:text-accent-foreground"
:aria-current="isPresetSelected(preset)"
size="sm"
variant="ghost"
@click="onPresetSelected(preset)"
@click="onPresetSelect(preset)"
>
{{ preset.label }}
</Button>
Expand Down
14 changes: 10 additions & 4 deletions resources/js/filters/components/filters/DateRangeFilterValue.vue
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
<script setup lang="ts">
import { DateRangeFilterData } from "@/types";
import { DateRangeFilterData, DateRangePresetData } from "@/types";
import { Badge } from "@/components/ui/badge";
import { FilterProps } from "@/filters/types";

const props = defineProps<FilterProps<DateRangeFilterData>>();
const props = defineProps<FilterProps<DateRangeFilterData> & { preset: DateRangePresetData|null }>();
</script>

<template>
<Badge
v-if="'start' in props.value"
variant="secondary"
class="rounded-sm px-1 font-normal"
class=" rounded-sm px-1 font-normal"
>
<template v-if="preset">
<span class="mr-2">
{{ preset.label }}:
</span>
</template>

<template v-if="props.value.end">
{{ props.value.formatted.start }} - {{ props.value.formatted.end }}
{{ props.value.formatted.start }} <span class="mx-1.5">-</span> {{ props.value.formatted.end }}
</template>

<template v-else>
Expand Down
8 changes: 6 additions & 2 deletions resources/js/types/generated.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,18 @@ export type DateRangeFilterData = {
start: string;
end: string;
formatted?: { start: string; end: string };
preset?: string;
} | null;
key: string;
label: string | null;
type: "daterange";
required: boolean;
mondayFirst: boolean;
presets: Array<{ key: string; label: string }> | null;
presets: Array<DateRangePresetData> | null;
};
export type DateRangePresetData = {
label: string | null;
start: string | null;
end: string | null;
};
export type EmbedData = {
value?: FormData["data"] & { slot: string; _html: string };
Expand Down
3 changes: 1 addition & 2 deletions src/Data/Filters/DateRangeFilterData.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ final class DateRangeFilterData extends Data
start: string,
end: string,
formatted?: { start: string, end: string },
preset?: string,
} | null')]
public ?array $value;

Expand All @@ -28,7 +27,7 @@ public function __construct(
public FilterType $type,
public bool $required,
public bool $mondayFirst,
#[LiteralTypeScriptType('Array<{ key:string, label:string }>|null')]
/** @var DateRangePresetData[] */
public ?array $presets,
) {}

Expand Down
22 changes: 22 additions & 0 deletions src/Data/Filters/DateRangePresetData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Code16\Sharp\Data\Filters;

use Code16\Sharp\Data\Data;

/**
* @internal
*/
final class DateRangePresetData extends Data
{
public function __construct(
public ?string $label,
public ?string $start,
public ?string $end,
) {}

public static function from(array $filter): self
{
return new self(...$filter);
}
}
88 changes: 88 additions & 0 deletions src/Filters/DateRange/DateRangePreset.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,98 @@ public function getEnd(): Carbon
return $this->end;
}

public static function make(Carbon $start, Carbon $end, string $label): self
{
return new static($start, $end, $label);
}

public static function today(): self
{
return new static(
Carbon::today(),
Carbon::today(),
__('sharp::filters.daterange.preset.today'),
);
}

public static function yesterday(): self
{
return new static(
Carbon::yesterday(),
Carbon::yesterday(),
__('sharp::filters.daterange.preset.yesterday'),
);
}

public static function last7days(): self
{
return new static(
Carbon::today()->subDays(6),
Carbon::today(),
__('sharp::filters.daterange.preset.last_7_days'),
);
}

public static function last30days(): self
{
return new static(
Carbon::today()->subDays(29),
Carbon::today(),
__('sharp::filters.daterange.preset.last_30_days'),
);
}

public static function last365days(): self
{
return new static(
Carbon::today()->subDays(364),
Carbon::today(),
__('sharp::filters.daterange.preset.last_365_days'),
);
}

public static function thisMonth(): self
{
return new static(
Carbon::today()->startOfMonth(),
Carbon::today()->endOfMonth(),
__('sharp::filters.daterange.preset.this_month'),
);
}

public static function lastMonth(): self
{
return new static(
Carbon::today()->subMonth()->startOfMonth(),
Carbon::today()->subMonth()->endOfMonth(),
__('sharp::filters.daterange.preset.last_month'),
);
}

public static function thisYear(): self
{
return new static(
Carbon::today()->startOfYear(),
Carbon::today()->endOfYear(),
__('sharp::filters.daterange.preset.this_year'),
);
}

public static function lastYear(): self
{
return new static(
Carbon::today()->subYear()->startOfYear(),
Carbon::today()->subYear()->endOfYear(),
__('sharp::filters.daterange.preset.last_year'),
);
}

public function toArray()
{
return [
'label' => $this->label,
'start' => $this->start->format('Y-m-d'),
'end' => $this->end->format('Y-m-d'),
];
}
}
Loading
Loading