New: Sidebar and Mandantenwechsel
This commit is contained in:
23
src/features/CRM/components/detail.tsx
Normal file
23
src/features/CRM/components/detail.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { useAnsprechpartner, useAnsprechpartnerEditMutation } from '../queries'
|
||||
|
||||
function AnsprechpartnerDetail({ id }: { id: number }) {
|
||||
const { data } = useAnsprechpartner(id)
|
||||
const { mutate } = useAnsprechpartnerEditMutation()
|
||||
|
||||
return (
|
||||
<div>
|
||||
{JSON.stringify(data)}
|
||||
<button
|
||||
onClick={(e) => {
|
||||
const newAnsprechparter = data!
|
||||
newAnsprechparter.first_name += '1'
|
||||
mutate(newAnsprechparter)
|
||||
}}
|
||||
>
|
||||
Edit Ansprechpartner
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AnsprechpartnerDetail
|
||||
73
src/features/CRM/queries.ts
Normal file
73
src/features/CRM/queries.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
|
||||
const ansprechpartnerKeys = {
|
||||
all: ['ansprechpartner'] as const,
|
||||
lists: () => [...ansprechpartnerKeys.all, 'list'] as const,
|
||||
details: () => [...ansprechpartnerKeys.all, 'detail'] as const,
|
||||
detail: (id: number) => [...ansprechpartnerKeys.details(), id] as const,
|
||||
}
|
||||
|
||||
type Ansprechpartner = {
|
||||
ID: number
|
||||
CreatedAt: Date
|
||||
UpdatedAt: Date | undefined
|
||||
DeletedAt: Date | undefined
|
||||
image_url: string
|
||||
title: string
|
||||
first_name: string
|
||||
last_name: string
|
||||
last_title: string
|
||||
e_mail: string
|
||||
phone: string
|
||||
mobile: string
|
||||
notes: string
|
||||
description: string
|
||||
active: boolean
|
||||
gender: number
|
||||
}
|
||||
|
||||
export function useAllAnsprechpartners() {
|
||||
return useQuery<Ansprechpartner>({
|
||||
queryKey: ansprechpartnerKeys.lists(),
|
||||
queryFn: async () => {
|
||||
const data = await fetch('http://localhost:3000/v1/ansprechpartner/all')
|
||||
return await data.json()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function useAnsprechpartner(id: number) {
|
||||
return useQuery<Ansprechpartner>({
|
||||
queryKey: ansprechpartnerKeys.detail(id),
|
||||
queryFn: async () => {
|
||||
const data = await fetch('http://localhost:3000/v1/ansprechpartner/' + id)
|
||||
return await data.json()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function useAnsprechpartnerEditMutation() {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (ansprechpartner: Ansprechpartner) => {
|
||||
const res = await fetch(
|
||||
'http://localhost:3000/v1/ansprechpartner/' + ansprechpartner.ID,
|
||||
{
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(ansprechpartner),
|
||||
},
|
||||
)
|
||||
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [
|
||||
ansprechpartnerKeys.detail(ansprechpartner.ID),
|
||||
ansprechpartnerKeys.lists(),
|
||||
],
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
123
src/features/Mandant/components/team-switcher.tsx
Normal file
123
src/features/Mandant/components/team-switcher.tsx
Normal file
@ -0,0 +1,123 @@
|
||||
import { useEffect } from 'react'
|
||||
import { ChevronDown, Plus } from 'lucide-react'
|
||||
|
||||
import {
|
||||
useAllMandanten,
|
||||
useCurrentMandant,
|
||||
useCurrentMandantMutation,
|
||||
} from '../queries'
|
||||
import type { Mandant } from '../queries'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu'
|
||||
import {
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
} from '@/components/ui/sidebar'
|
||||
|
||||
export function TeamSwitcher() {
|
||||
const { data: currentMandant } = useCurrentMandant()
|
||||
const { data: mandanten } = useAllMandanten()
|
||||
|
||||
const { mutate } = useCurrentMandantMutation()
|
||||
|
||||
useEffect(() => {
|
||||
console.log('AddEvent')
|
||||
const down = (e: KeyboardEvent) => {
|
||||
console.log('Keydown: ' + e.key)
|
||||
|
||||
let numKey = Number(e.key)
|
||||
|
||||
if ((e.metaKey || e.ctrlKey) && !Number.isNaN(numKey)) {
|
||||
console.log('CMD | META-before & ' + numKey)
|
||||
|
||||
numKey -= 1
|
||||
|
||||
console.log('CMD | META & ' + numKey)
|
||||
if (mandanten) {
|
||||
mutate(mandanten[numKey])
|
||||
console.log('MUTATED ' + mandanten[numKey])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', down)
|
||||
return () => document.removeEventListener('keydown', down)
|
||||
}, [mandanten])
|
||||
|
||||
if (!currentMandant || !mandanten) return <p>Loading...</p>
|
||||
|
||||
return (
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<SidebarMenuButton className="w-full h-full">
|
||||
<div
|
||||
className="text-sidebar-primary-foreground flex aspect-square size-8 rounded-lg items-center justify-center"
|
||||
style={{ backgroundColor: currentMandant.color }}
|
||||
>
|
||||
<img className="size-4" src={currentMandant.logo} />
|
||||
</div>
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-medium">
|
||||
{currentMandant.name}
|
||||
</span>
|
||||
<span className="truncate text-xs">{currentMandant.plan}</span>
|
||||
</div>
|
||||
<ChevronDown className="ml-auto opacity-50" />
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
className="w-64 rounded-lg"
|
||||
align="start"
|
||||
side="bottom"
|
||||
sideOffset={4}
|
||||
>
|
||||
<DropdownMenuLabel className="text-muted-foreground text-xs">
|
||||
Teams
|
||||
</DropdownMenuLabel>
|
||||
{mandanten.map((mandant, index) => {
|
||||
return <MandantDMI mandant={mandant} index={index} />
|
||||
})}
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem className="gap-2 p-2">
|
||||
<div className="bg-background flex size-6 items-center justify-center rounded-md border">
|
||||
<Plus className="size-4" />
|
||||
</div>
|
||||
<div className="text-muted-foreground font-medium">Add team</div>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
)
|
||||
}
|
||||
|
||||
function MandantDMI({ mandant, index }: { mandant: Mandant; index: number }) {
|
||||
const { mutate } = useCurrentMandantMutation()
|
||||
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={mandant.name}
|
||||
onClick={() => mutate(mandant)}
|
||||
className="gap-2 p-2"
|
||||
>
|
||||
<div
|
||||
className="flex size-6 items-center justify-center rounded-sm border"
|
||||
style={{ backgroundColor: mandant.color }}
|
||||
>
|
||||
<img className="size-4 shrink-0" src={mandant.logo} />
|
||||
</div>
|
||||
{mandant.name}
|
||||
<DropdownMenuShortcut>⌘{index + 1}</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
)
|
||||
}
|
||||
56
src/features/Mandant/queries.ts
Normal file
56
src/features/Mandant/queries.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
|
||||
const mandantKeys = {
|
||||
all: ['mandant'] as const,
|
||||
lists: () => [...mandantKeys.all, 'list'] as const,
|
||||
current: () => [...mandantKeys.all, 'current'] as const,
|
||||
}
|
||||
|
||||
export type Mandant = {
|
||||
id: string
|
||||
name: string
|
||||
logo: string
|
||||
plan: string
|
||||
color: string
|
||||
}
|
||||
|
||||
export function useCurrentMandant() {
|
||||
return useQuery<Mandant>({
|
||||
queryKey: mandantKeys.current(),
|
||||
queryFn: async () => {
|
||||
const data = await fetch('http://localhost:3000/v1/mandant/current')
|
||||
return await data.json()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function useAllMandanten() {
|
||||
return useQuery<Array<Mandant>>({
|
||||
queryKey: mandantKeys.lists(),
|
||||
queryFn: async () => {
|
||||
const data = await fetch('http://localhost:3000/v1/mandant/all')
|
||||
return await data.json()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function useCurrentMandantMutation() {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (mandant: Mandant) => {
|
||||
const res = await fetch('http://localhost:3000/v1/mandant/current', {
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(mandant),
|
||||
})
|
||||
const newCurrentMandant = await res.json()
|
||||
queryClient.setQueryData(
|
||||
mandantKeys.current(),
|
||||
(_: Mandant) => newCurrentMandant,
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user