Skip to content

Commit

Permalink
Merge branch 'ryan/world-887-point-to-new-endpoint' into ryan/world-9…
Browse files Browse the repository at this point in the history
…07-edit-remove-entity-groups
  • Loading branch information
rmrt1n authored Mar 4, 2024
2 parents fd2047c + f726895 commit bf84a2f
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 0 deletions.
113 changes: 113 additions & 0 deletions src/components/entity-group-sheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { useState } from 'react';

import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from '@/components/ui/sheet';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
import { MultiSelect } from '@/components/multi-select';
import { EntityCard } from '@/components/entity-views';
import { useQuery } from '@tanstack/react-query';
import { Entity, WorldResponse } from '@/lib/types';
import { useCardinal } from '@/lib/cardinal-provider';
import { worldQueryOptions } from '@/lib/query-options';
import { useConfig } from '@/lib/config-provider';

// TODO: update this when registered components endpoint is done
const sampleEntity = (components: string[]): Entity => {
return {
id: 0,
components: components.reduce((acc, c) => ({ ...acc, [c]: { attribute: 'dummy data' } }), {})
}
}

// TODO: consider zod for form vaidation
export function EntityGroupSheet() {
const cardinal = useCardinal()
const { data } = useQuery<WorldResponse>(worldQueryOptions(cardinal))
const { config, setConfig } = useConfig()
const [entityGroupName, setEntityGroupName] = useState('')
const [entityGroupError, setEntityGroupError] = useState('')
const [selected, setSelected] = useState<string[]>([])
const [selectedError, setSelectedError] = useState('')

const components = data?.components.map((c) => ({ label: c, value: c })) ?? []
const hasSelectedComponents = selected && selected.length > 0
const accordionValue = hasSelectedComponents ? "default" : ""

const handleClick = (e: React.MouseEvent<HTMLElement>) => {
if (entityGroupName.length === 0) {
e.preventDefault()
setEntityGroupError('Please enter a name for the entity group')
}
if (selected.length === 0) {
e.preventDefault()
setSelectedError('Please select at least 1 component')
return
}
const newEntityGroup = {
name: entityGroupName,
components: selected
}
// TODO: check for duplicates
setConfig({ ...config, entityGroups: [...config.entityGroups, newEntityGroup] })
}

return (
<>
<Sheet>
<SheetTrigger asChild>
<Button>New Entity Group</Button>
</SheetTrigger>
<SheetContent className="flex flex-col justify-between">
<div>
<SheetHeader>
<SheetTitle>New Entity Group</SheetTitle>
<SheetDescription>
You can create "entity groups" by grouping different components. It acts as a filter
to only show entities containing the components you specify.
</SheetDescription>
</SheetHeader>
<div className="space-y-4 mt-4">
<div className="space-y-1">
<Label>Entity group name</Label>
<Input
required
value={entityGroupName}
onChange={(e) => setEntityGroupName(e.target.value)}
placeholder="New entity group..."
/>
<small className="text-destructive">{entityGroupError}</small>
</div>
<div className="space-y-1">
<Label>Components</Label>
<MultiSelect options={components} selected={selected} onChange={setSelected} />
<small className="text-destructive">{selectedError}</small>
</div>
<Accordion
collapsible
type="single"
value={accordionValue}
className="bg-muted border border-border rounded-lg px-3 py-1"
>
<AccordionItem value="default" className="border-0 space-y-2">
<AccordionTrigger className="py-2 text-sm">Sample entities</AccordionTrigger>
<AccordionContent>
{hasSelectedComponents && (
<EntityCard entity={sampleEntity(selected)} />
)}
</AccordionContent>
</AccordionItem>
</Accordion>
</div>
</div>
<SheetFooter className="mt-auto">
<SheetClose asChild>
<Button onClick={handleClick}>Create Entity Group</Button>
</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>
</>
)
}
4 changes: 4 additions & 0 deletions src/components/entity-views.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
import { Badge } from "@/components/ui/badge"
import { useConfig } from "@/lib/config-provider"
import { Entity } from "@/lib/types"
import { Edit } from "lucide-react"
import { Button } from "./ui/button"

interface EntityCardsListProps {
entities: Entity[]
Expand Down
71 changes: 71 additions & 0 deletions src/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,74 @@ function SideBarItem({ item }: SideBarItemProps) {
</>
)
}

interface SideBarItemProps {
item: {
title: string,
icon: React.ReactNode,
items: MessageOrQuery[]
}
}

function SideBarItem({ item }: SideBarItemProps) {
const items = item.items
const formatName = (name: string) => {
let s = name.replace(/-/g, ' ')
return s.charAt(0).toUpperCase() + s.slice(1)
}

return (
<>
<Accordion collapsible type="single" defaultValue="default">
<AccordionItem value="default" className="border-0">
<AccordionTrigger className="px-2">
<p className="flex items-center gap-2 font-bold">{item.icon} {item.title}</p>
</AccordionTrigger>
<AccordionContent className="space-y-2">
{items.length > 0 ? (
items.map((item, i) => (
<Accordion
collapsible
key={i}
type="single"
className="bg-muted border border-border rounded-lg"
>
<AccordionItem value="default" className="border-0 [&_.params]:data-[state=open]:hidden">
<AccordionTrigger
title={formatName(item.name)}
className="p-2 max-w-full rounded-lg border-border data-[state=closed]:border-b data-[state=closed]:bg-background"
>
<p className="text-sm text-left max-w-[85%] truncate">{formatName(item.name)}</p>
</AccordionTrigger>
<div className="params px-2 py-0.5 font-medium text-xs text-muted-foreground truncate">
{Object.keys(item.fields).join(', ')}
</div>
<AccordionContent className="p-2 space-y-2">
{Object.keys(item.fields).map((param) => (
<div key={param} className="space-y-1">
<p className="font-medium space-x-2">
<span>{param}</span>
<span className="text-muted-foreground font-normal">{item.fields[param]}</span>
</p>
<Input className="h-8" />
</div>
))}
<Button className="w-full h-8">Send</Button>
</AccordionContent>
</AccordionItem>
</Accordion>
))
) : (
<div className="flex flex-col gap-4 items-center bg-muted text-muted-foreground py-4 rounded-lg">
<BookDashed size={24} strokeWidth={2.5} />
<div className="space-y-2 text-center">
<p className="text-xs font-semibold">No {item.title} Found</p>
</div>
</div>
)}
</AccordionContent>
</AccordionItem>
</Accordion>
</>
)
}

0 comments on commit bf84a2f

Please sign in to comment.