Move user menu to sidebar, fixes #35
This commit is contained in:
@@ -7,27 +7,21 @@ import PlaceholderPattern from '../components/PlaceholderPattern.vue';
|
||||
|
||||
<template>
|
||||
|
||||
<Head title="Erfolge" />
|
||||
<AppLayout title="Erfolge">
|
||||
<div>
|
||||
<h1 class="text-xl">Kategorie</h1>
|
||||
<h2 class="text-sm text-neutral-400 mb-4">3 von 10 freigeschaltet</h2>
|
||||
|
||||
<AppLayout>
|
||||
<div class="flex h-full flex-1 flex-col gap-4 overflow-x-auto rounded-xl p-4">
|
||||
|
||||
<div>
|
||||
<h1 class="text-xl">Kategorie</h1>
|
||||
<h2 class="text-sm text-neutral-400 mb-4">3 von 10 freigeschaltet</h2>
|
||||
|
||||
<div class="flex flex-row flex-wrap gap-4">
|
||||
<div v-for="n in 10" class="relative flex flex-col items-center">
|
||||
<div
|
||||
class="w-48 relative aspect-square overflow-hidden rounded-full border border-sidebar-border/70 dark:border-sidebar-border">
|
||||
<PlaceholderPattern />
|
||||
</div>
|
||||
<label class="">Erfolg {{ n
|
||||
}}</label>
|
||||
<div class="flex flex-row flex-wrap gap-4">
|
||||
<div v-for="n in 10" class="relative flex flex-col items-center">
|
||||
<div
|
||||
class="w-48 relative aspect-square overflow-hidden rounded-full border border-sidebar-border/70 dark:border-sidebar-border">
|
||||
<PlaceholderPattern />
|
||||
</div>
|
||||
<label class="">Erfolg {{ n
|
||||
}}</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
+135
-138
@@ -1,19 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import { ref, onMounted, computed, useTemplateRef, watch } from 'vue'
|
||||
import { ref, onMounted, computed, watch } from 'vue'
|
||||
import AppLayout from '@/layouts/AppLayout.vue'
|
||||
import { customers } from '@/routes'
|
||||
import AppHeader from '@/components/AppHeader.vue'
|
||||
import { Address } from '@/types'
|
||||
import { Head } from '@inertiajs/vue3'
|
||||
import api from '@/axios'
|
||||
import { Customer, Contact } from '@/types'
|
||||
import { randomInt, bgColorForString } from '@/lib/utils'
|
||||
import { Customer } from '@/types'
|
||||
import { bgColorForString } from '@/lib/utils'
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, } from '@/components/ui/button-group'
|
||||
import { Copy, Delete, Edit, Globe, House, LayoutGrid, LayoutList, Mail, Phone, Plus, Rows3, Rows4, Search, Smartphone } from "lucide-vue-next"
|
||||
import { ButtonGroup } from '@/components/ui/button-group'
|
||||
import { Delete, Globe, House, LayoutGrid, Mail, Phone, Plus, Rows3, Search, Smartphone } from "lucide-vue-next"
|
||||
import Fuse from 'fuse.js';
|
||||
import { getInitials } from '@/composables/useInitials';
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from '@/components/ui/card'
|
||||
@@ -121,15 +120,11 @@ const call = (number: string, event: Event) => {
|
||||
|
||||
<template>
|
||||
|
||||
<Head title="Dashboard" />
|
||||
<AppLayout title="Kunden">
|
||||
|
||||
<AppLayout>
|
||||
<div
|
||||
class="flex h-full flex-1 flex-col gap-4 overflow-x-auto p-4 lg:p-8 print:bg-transparent print:p-0 print:m-0">
|
||||
|
||||
<!-- Function Header -->
|
||||
<div id="function-header" class="flex row justify-between items-center mb-4 gap-4">
|
||||
<!-- View buttons -->
|
||||
<AppHeader>
|
||||
<!-- View buttons -->
|
||||
<template #left>
|
||||
<ButtonGroup aria-label="Button group">
|
||||
<Button variant="pressed" size="sm">
|
||||
<LayoutGrid stroke-width="1.5" />
|
||||
@@ -138,150 +133,152 @@ const call = (number: string, event: Event) => {
|
||||
<Rows3 stroke-width="1.5" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</template>
|
||||
|
||||
<!-- Search field -->
|
||||
<div class="relative w-full max-w-sm items-center">
|
||||
<Input ref="search-field" id="search" type="text" placeholder="Filtern" class="px-8 bg-background"
|
||||
v-model="searchQuery" />
|
||||
<span class="absolute start-0 inset-y-0 flex items-center justify-center px-2">
|
||||
<Search class="size-4 text-muted-foreground" :stroke-width="1.5" />
|
||||
</span>
|
||||
<span class="absolute end-0 inset-y-0 flex items-center justify-center px-0 mr-1">
|
||||
<Button :size="'sm'" :variant="'ghost'" @click="searchQuery = ''; searchField.focus()">
|
||||
<Delete class="size-4 text-muted-foreground" :stroke-width="1.5" />
|
||||
</Button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- New button -->
|
||||
<!-- Search field -->
|
||||
<template #middle>
|
||||
<Input ref="search-field" id="search" type="text" placeholder="Filtern" class="px-8 bg-background"
|
||||
v-model="searchQuery" />
|
||||
<span class="absolute start-0 inset-y-0 flex items-center justify-center px-2">
|
||||
<Search class="size-4 text-muted-foreground" :stroke-width="1.5" />
|
||||
</span>
|
||||
<span class="absolute end-0 inset-y-0 flex items-center justify-center px-0 mr-1">
|
||||
<Button :size="'sm'" :variant="'ghost'" @click="searchQuery = ''; searchField.focus()">
|
||||
<Delete class="size-4 text-muted-foreground" :stroke-width="1.5" />
|
||||
</Button>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<!-- New button -->
|
||||
<template #right>
|
||||
<Button size="sm" variant="action" @click="">
|
||||
<Plus stroke-width="1.5" /> Neu
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</AppHeader>
|
||||
|
||||
|
||||
<div class="columns-xs gap-6">
|
||||
<div class="columns-xs gap-6">
|
||||
|
||||
<Card v-for="customer in filteredCustomers" :key="customer.id"
|
||||
class="relative mb-6 break-inside-avoid hover:border-slate-300 dark:hover:bg-neutral-800/90 dark:hover:border-neutral-600 overflow-clip"
|
||||
@click="showDetail(customer)">
|
||||
<Card v-for="customer in filteredCustomers" :key="customer.id"
|
||||
class="relative mb-6 break-inside-avoid hover:border-slate-300 dark:hover:bg-neutral-800/90 dark:hover:border-neutral-600 overflow-clip"
|
||||
@click="showDetail(customer)">
|
||||
|
||||
<CardHeader v-if="customer.logo" class="z-0">
|
||||
<img :src="'storage/uploads/' + customer.logo" alt="Logo {{ customer.companyName }}"
|
||||
class="max-h-8 max-w-[50%]">
|
||||
</CardHeader>
|
||||
<CardHeader v-if="customer.logo" class="z-0">
|
||||
<img :src="'storage/uploads/' + customer.logo" alt="Logo {{ customer.companyName }}"
|
||||
class="max-h-8 max-w-[50%]">
|
||||
</CardHeader>
|
||||
|
||||
<CardContent class="flex justify-between gap-4 flex-col sm:flex-row pr-4 z-0">
|
||||
<address class="not-italic">
|
||||
<CardTitle>
|
||||
{{ customer.companyName }}
|
||||
<!-- <Badge variant="secondary">Badge</Badge> -->
|
||||
</CardTitle>
|
||||
<CardDescription class="mt-2">
|
||||
{{ customer.billingAddress?.lineOne }}<br />
|
||||
{{ customer.billingAddress?.lineTwo }}<br v-if="customer.billingAddress?.lineTwo" />
|
||||
{{ customer.billingAddress?.postalCode }} {{ customer.billingAddress?.city }}
|
||||
</CardDescription>
|
||||
</address>
|
||||
<CardContent class="flex justify-between gap-4 flex-col sm:flex-row pr-4 z-0">
|
||||
<address class="not-italic">
|
||||
<CardTitle>
|
||||
{{ customer.companyName }}
|
||||
<!-- <Badge variant="secondary">Badge</Badge> -->
|
||||
</CardTitle>
|
||||
<CardDescription class="mt-2">
|
||||
{{ customer.billingAddress?.lineOne }}<br />
|
||||
{{ customer.billingAddress?.lineTwo }}<br v-if="customer.billingAddress?.lineTwo" />
|
||||
{{ customer.billingAddress?.postalCode }} {{ customer.billingAddress?.city }}
|
||||
</CardDescription>
|
||||
</address>
|
||||
|
||||
<div class="flex items-start">
|
||||
<TooltipProvider>
|
||||
<Tooltip v-if="customer.url">
|
||||
<TooltipTrigger>
|
||||
<Button variant="ghost" size="sm"
|
||||
@click="(event: Event) => browse(customer.url as string, event)">
|
||||
<Globe stroke-width="1.5" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{{ customer.url }} öffnen
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip v-if="customer.phone">
|
||||
<TooltipTrigger>
|
||||
<Button variant="ghost" size="sm"
|
||||
@click="(event: Event) => call(customer.phone as string, event)">
|
||||
<Phone stroke-width="1.5" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{{ customer.phone }} anrufen
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip v-if="customer.billingAddress">
|
||||
<TooltipTrigger>
|
||||
<Button variant="ghost" size="sm"
|
||||
@click="(event: Event) => addressToClipbard(customer.companyName, customer.billingAddress as Address | null, event)">
|
||||
<House stroke-width="1.5" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
Adresse in Zwischenablage kopieren
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
<CardFooter v-if="customer.contacts.length > 0">
|
||||
<TooltipProvider :delay-duration="0">
|
||||
|
||||
<Tooltip v-for="contact in customer.contacts">
|
||||
<div class="flex items-start">
|
||||
<TooltipProvider>
|
||||
<Tooltip v-if="customer.url">
|
||||
<TooltipTrigger>
|
||||
<Avatar class="size-14 shadow -mr-2">
|
||||
<AvatarImage v-if="contact.avatar" :src="'/storage/uploads/' + contact.avatar"
|
||||
loading="lazy" />
|
||||
<AvatarFallback
|
||||
:class="bgColorForString(getInitials(contact.firstName + ' ' + contact.lastName))">
|
||||
{{ getInitials(contact.firstName + ' ' + contact.lastName) }}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<Button variant="ghost" size="sm"
|
||||
@click="(event: Event) => browse(customer.url as string, event)">
|
||||
<Globe stroke-width="1.5" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent class="p-4 -mr-2" :side-offset="-1">
|
||||
<p class="font-bold">
|
||||
<span v-if="contact.academicTitle">{{ contact.academicTitle }}</span>
|
||||
<span>{{ contact.firstName + ' ' + contact.lastName }}</span>
|
||||
</p>
|
||||
<p v-if="contact.jobTitle" class="text-muted-foreground">{{ contact.jobTitle }}</p>
|
||||
|
||||
<ButtonGroup class="mt-4">
|
||||
<!-- E-mail -->
|
||||
<Button size="sm" v-if="contact.email"
|
||||
@click="(event: Event) => mail(contact.email as string, event)">
|
||||
<Mail stroke-width="1.5" @click="" />
|
||||
</Button>
|
||||
<!-- Phone -->
|
||||
<Button size="sm" v-if="contact.phone"
|
||||
@click="(event: Event) => call(contact.phone as string, event)">
|
||||
<Phone stroke-width="1.5" @click="" />
|
||||
</Button>
|
||||
<!-- Mobile phone -->
|
||||
<Button size="sm" v-if="contact.mobilePhone"
|
||||
@click="(event: Event) => call(contact.mobilePhone as string, event)">
|
||||
<Smartphone stroke-width="1.5" @click="" />
|
||||
</Button>
|
||||
<!-- Online accounts -->
|
||||
<Button size="sm" v-for="account in contact.onlineAccounts"
|
||||
@click="(event: Event) => browse(account.url as string, event)">
|
||||
<SocialIcon :variant="account.platform" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<TooltipArrow :height="8" :width="16"
|
||||
class="fill-popover drop-shadow-(--shadow-arrow) stroke-[0.5px] stroke-border -mt-[1px]" />
|
||||
<TooltipContent>
|
||||
{{ customer.url }} öffnen
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip v-if="customer.phone">
|
||||
<TooltipTrigger>
|
||||
<Button variant="ghost" size="sm"
|
||||
@click="(event: Event) => call(customer.phone as string, event)">
|
||||
<Phone stroke-width="1.5" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{{ customer.phone }} anrufen
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip v-if="customer.billingAddress">
|
||||
<TooltipTrigger>
|
||||
<Button variant="ghost" size="sm"
|
||||
@click="(event: Event) => addressToClipbard(customer.companyName, customer.billingAddress as Address | null, event)">
|
||||
<House stroke-width="1.5" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
Adresse in Zwischenablage kopieren
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
</TooltipProvider>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
</div>
|
||||
<CardFooter v-if="customer.contacts.length > 0">
|
||||
<TooltipProvider :delay-duration="0">
|
||||
|
||||
<!-- Invoice detail dialog -->
|
||||
<CustomerDialog :customerData="activeCustomer" v-model="detailDialogOpen" @save="" @delete="" />
|
||||
<Tooltip v-for="contact in customer.contacts">
|
||||
<TooltipTrigger>
|
||||
<Avatar class="size-14 shadow -mr-2">
|
||||
<AvatarImage v-if="contact.avatar" :src="'/storage/uploads/' + contact.avatar"
|
||||
loading="lazy" />
|
||||
<AvatarFallback
|
||||
:class="bgColorForString(getInitials(contact.firstName + ' ' + contact.lastName))">
|
||||
{{ getInitials(contact.firstName + ' ' + contact.lastName) }}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent class="p-4 -mr-2" :side-offset="-1">
|
||||
<p class="font-bold">
|
||||
<span v-if="contact.academicTitle">{{ contact.academicTitle }}</span>
|
||||
<span>{{ contact.firstName + ' ' + contact.lastName }}</span>
|
||||
</p>
|
||||
<p v-if="contact.jobTitle" class="text-muted-foreground">{{ contact.jobTitle }}</p>
|
||||
|
||||
<ButtonGroup class="mt-4">
|
||||
<!-- E-mail -->
|
||||
<Button size="sm" v-if="contact.email"
|
||||
@click="(event: Event) => mail(contact.email as string, event)">
|
||||
<Mail stroke-width="1.5" @click="" />
|
||||
</Button>
|
||||
<!-- Phone -->
|
||||
<Button size="sm" v-if="contact.phone"
|
||||
@click="(event: Event) => call(contact.phone as string, event)">
|
||||
<Phone stroke-width="1.5" @click="" />
|
||||
</Button>
|
||||
<!-- Mobile phone -->
|
||||
<Button size="sm" v-if="contact.mobilePhone"
|
||||
@click="(event: Event) => call(contact.mobilePhone as string, event)">
|
||||
<Smartphone stroke-width="1.5" @click="" />
|
||||
</Button>
|
||||
<!-- Online accounts -->
|
||||
<Button size="sm" v-for="account in contact.onlineAccounts"
|
||||
@click="(event: Event) => browse(account.url as string, event)">
|
||||
<SocialIcon :variant="account.platform" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<TooltipArrow :height="8" :width="16"
|
||||
class="fill-popover drop-shadow-(--shadow-arrow) stroke-[0.5px] stroke-border -mt-[1px]" />
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
</TooltipProvider>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Invoice detail dialog -->
|
||||
<CustomerDialog :customerData="activeCustomer" v-model="detailDialogOpen" @save="" @delete="" />
|
||||
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -27,10 +27,8 @@ if (token) {
|
||||
|
||||
<template>
|
||||
|
||||
<Head title="Dashboard" />
|
||||
|
||||
<AppLayout>
|
||||
<div class="grid gap-12 md:grid-cols-2 h-full p-6 md:p-8">
|
||||
<AppLayout title="Dashboard">
|
||||
<div class="grid gap-12 md:grid-cols-2 h-full md:p-8">
|
||||
|
||||
<div class="relative overflow-y-auto">
|
||||
Geplante Aktivitäten
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import AppLayout from '@/layouts/AppLayout.vue'
|
||||
import { invoices } from '@/routes'
|
||||
import { computed, ref, onMounted, watch, defineProps, HTMLAttributes } from 'vue'
|
||||
import { type Invoice, type Customer, type Address } from '@/types'
|
||||
import { newInvoice } from '@/types/index.d'
|
||||
import { Head } from '@inertiajs/vue3'
|
||||
import { computed, ref, onMounted, watch } from 'vue'
|
||||
import axios, { Axios, AxiosError, AxiosResponse } from 'axios'
|
||||
import axios from 'axios'
|
||||
import AppLayout from '@/layouts/AppLayout.vue'
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue, } from '@/components/ui/select'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import DocumentTable from '@/components/documents/DocumentTable.vue'
|
||||
@@ -15,11 +13,11 @@ import InvoiceDialog from '@/components/documents/InvoiceDialog.vue'
|
||||
import Fuse from 'fuse.js';
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { toast } from 'vue-sonner'
|
||||
import { testToast } from '@/lib/utils'
|
||||
import SelectSeparator from '@/components/ui/select/SelectSeparator.vue'
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { Kbd, KbdGroup } from '@/components/ui/kbd'
|
||||
import { statusBadgeLabels } from '@/components/ui/status-badge'
|
||||
import AppHeader from '@/components/AppHeader.vue'
|
||||
|
||||
const invoicesData = ref([] as Invoice[])
|
||||
const activeInvoice = ref<Invoice | null>(null)
|
||||
@@ -191,62 +189,54 @@ const deleteInvoice = async (id: number) => {
|
||||
|
||||
<template>
|
||||
|
||||
<Head title="Rechnungen" />
|
||||
|
||||
|
||||
<!-- Function Header -->
|
||||
<AppLayout>
|
||||
<AppLayout title="Rechnungen">
|
||||
|
||||
<div
|
||||
class="flex h-full flex-1 flex-col gap-4 overflow-x-auto p-4 lg:p-8 lg:pl-4 print:bg-transparent print:p-0 print:m-0">
|
||||
<AppHeader>
|
||||
<!-- Year select -->
|
||||
<template #left>
|
||||
<Button variant="ghost" :disabled="selectedYearIndex >= (years.length - 1)"
|
||||
@click="selectedYearIndex++">
|
||||
<ChevronLeft />
|
||||
</Button>
|
||||
<Select size="sm" v-model="selectedYearIndex" v-if="years.length > 1">
|
||||
<SelectTrigger class=" hover:bg-accent">
|
||||
<SelectValue placeholder="Jahr" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem :value="null">
|
||||
<SelectLabel>Alle</SelectLabel>
|
||||
</SelectItem>
|
||||
<SelectSeparator />
|
||||
<SelectItem v-for="(year, index) in years" :value="index">
|
||||
<SelectLabel>{{ year }}</SelectLabel>
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="ghost" @click="selectedYearIndex--" :disabled="selectedYearIndex <= 0">
|
||||
<ChevronRight />
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<div id="function-header" class="flex row justify-between items-center mb-4 gap-4">
|
||||
|
||||
<!-- Year select -->
|
||||
<div class="flex row items-center">
|
||||
<Button :variant="'ghost'" :disabled="selectedYearIndex >= (years.length - 1)"
|
||||
@click="selectedYearIndex++">
|
||||
<ChevronLeft />
|
||||
<!-- Search field -->
|
||||
<template #middle>
|
||||
<Input ref="search-field" id="search" type="text" placeholder="Filtern" class="px-8 bg-background"
|
||||
v-model="searchQuery" />
|
||||
<span class="absolute start-0 inset-y-0 flex items-center justify-center px-2">
|
||||
<Search class="size-4 text-muted-foreground" :stroke-width="1.5" />
|
||||
</span>
|
||||
<span class="absolute end-0 inset-y-0 flex items-center justify-center px-0 mr-1">
|
||||
<Button :size="'sm'" :variant="'ghost'" @click="searchQuery = ''; searchField.focus()">
|
||||
<Delete class="size-4 text-muted-foreground" :stroke-width="1.5" />
|
||||
</Button>
|
||||
<Select :size="'sm'" v-model="selectedYearIndex" v-if="years.length > 1">
|
||||
<SelectTrigger class=" hover:bg-accent">
|
||||
<SelectValue placeholder="Jahr" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem :value="null">
|
||||
<SelectLabel>Alle</SelectLabel>
|
||||
</SelectItem>
|
||||
<SelectSeparator />
|
||||
<SelectItem v-for="(year, index) in years" :value="index">
|
||||
<SelectLabel>{{ year }}</SelectLabel>
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button :variant="'ghost'" @click="selectedYearIndex--" :disabled="selectedYearIndex <= 0">
|
||||
<ChevronRight />
|
||||
</Button>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<!-- Search field -->
|
||||
<div class="relative w-full max-w-sm items-center">
|
||||
<Input ref="search-field" id="search" type="text" placeholder="Filtern" class="px-8 bg-background"
|
||||
v-model="searchQuery" />
|
||||
<span class="absolute start-0 inset-y-0 flex items-center justify-center px-2">
|
||||
<Search class="size-4 text-muted-foreground" :stroke-width="1.5" />
|
||||
</span>
|
||||
<span class="absolute end-0 inset-y-0 flex items-center justify-center px-0 mr-1">
|
||||
<Button :size="'sm'" :variant="'ghost'" @click="searchQuery = ''; searchField.focus()">
|
||||
<Delete class="size-4 text-muted-foreground" :stroke-width="1.5" />
|
||||
</Button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- <Button size="sm" @click="testToast" class="mr-2">
|
||||
Toast
|
||||
</Button> -->
|
||||
|
||||
<!-- New button -->
|
||||
<!-- New button -->
|
||||
<template #right>
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
@@ -265,18 +255,17 @@ const deleteInvoice = async (id: number) => {
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</AppHeader>
|
||||
|
||||
<!-- Invoice Table -->
|
||||
<DocumentTable :invoices="filteredInvoices" :onItemClicked="showDetail" />
|
||||
|
||||
<!-- Invoice Table -->
|
||||
<DocumentTable :invoices="filteredInvoices" :onItemClicked="showDetail" />
|
||||
<!-- Invoice detail dialog -->
|
||||
<InvoiceDialog :invoiceData="activeInvoice" :customers="customersData" v-model="detailDialogOpen"
|
||||
@save="saveInvoice" @delete="deleteInvoice" />
|
||||
|
||||
<!-- Invoice detail dialog -->
|
||||
<InvoiceDialog :invoiceData="activeInvoice" :customers="customersData" v-model="detailDialogOpen"
|
||||
@save="saveInvoice" @delete="deleteInvoice" />
|
||||
|
||||
</div>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -25,52 +25,34 @@ const user = page.props.auth.user;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppLayout>
|
||||
<Head title="Profile settings" />
|
||||
<AppLayout title="Profile settings">
|
||||
|
||||
<SettingsLayout>
|
||||
<div class="flex flex-col space-y-6">
|
||||
<HeadingSmall title="Profile information" description="Update your name and email address" />
|
||||
|
||||
<Form v-bind="ProfileController.update.form()" class="space-y-6" v-slot="{ errors, processing, recentlySuccessful }">
|
||||
<Form v-bind="ProfileController.update.form()" class="space-y-6"
|
||||
v-slot="{ errors, processing, recentlySuccessful }">
|
||||
<div class="grid gap-2">
|
||||
<Label for="name">Name</Label>
|
||||
<Input
|
||||
id="name"
|
||||
class="mt-1 block w-full"
|
||||
name="name"
|
||||
:default-value="user.name"
|
||||
required
|
||||
autocomplete="name"
|
||||
placeholder="Full name"
|
||||
/>
|
||||
<Input id="name" class="mt-1 block w-full" name="name" :default-value="user.name" required
|
||||
autocomplete="name" placeholder="Full name" />
|
||||
<InputError class="mt-2" :message="errors.name" />
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="email">Email address</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
class="mt-1 block w-full"
|
||||
name="email"
|
||||
:default-value="user.email"
|
||||
required
|
||||
autocomplete="username"
|
||||
placeholder="Email address"
|
||||
/>
|
||||
<Input id="email" type="email" class="mt-1 block w-full" name="email"
|
||||
:default-value="user.email" required autocomplete="username" placeholder="Email address" />
|
||||
<InputError class="mt-2" :message="errors.email" />
|
||||
</div>
|
||||
|
||||
<div v-if="mustVerifyEmail && !user.email_verified_at">
|
||||
<p class="-mt-4 text-sm text-muted-foreground">
|
||||
Your email address is unverified.
|
||||
<Link
|
||||
:href="send()"
|
||||
as="button"
|
||||
class="text-foreground underline decoration-neutral-300 underline-offset-4 transition-colors duration-300 ease-out hover:decoration-current! dark:decoration-neutral-500"
|
||||
>
|
||||
Click here to resend the verification email.
|
||||
<Link :href="send()" as="button"
|
||||
class="text-foreground underline decoration-neutral-300 underline-offset-4 transition-colors duration-300 ease-out hover:decoration-current! dark:decoration-neutral-500">
|
||||
Click here to resend the verification email.
|
||||
</Link>
|
||||
</p>
|
||||
|
||||
@@ -81,28 +63,17 @@ const user = page.props.auth.user;
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="avatar">Avatar</Label>
|
||||
<Input
|
||||
id="avatar"
|
||||
type="avatar"
|
||||
class="mt-1 block w-full"
|
||||
name="avatar"
|
||||
:default-value="user.avatar"
|
||||
required
|
||||
autocomplete="username"
|
||||
placeholder="avatar address"
|
||||
/>
|
||||
<Input id="avatar" type="avatar" class="mt-1 block w-full" name="avatar"
|
||||
:default-value="user.avatar" required autocomplete="username"
|
||||
placeholder="avatar address" />
|
||||
<InputError class="mt-2" :message="errors.email" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<Button :disabled="processing" data-test="update-profile-button">Save</Button>
|
||||
|
||||
<Transition
|
||||
enter-active-class="transition ease-in-out"
|
||||
enter-from-class="opacity-0"
|
||||
leave-active-class="transition ease-in-out"
|
||||
leave-to-class="opacity-0"
|
||||
>
|
||||
<Transition enter-active-class="transition ease-in-out" enter-from-class="opacity-0"
|
||||
leave-active-class="transition ease-in-out" leave-to-class="opacity-0">
|
||||
<p v-show="recentlySuccessful" class="text-sm text-neutral-600">Saved.</p>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user