feat: edit area names

This commit is contained in:
Joshua Shoemaker 2023-01-04 22:19:02 -06:00
parent fe25bc1c2e
commit f01cd74a88
10 changed files with 230 additions and 42 deletions

Binary file not shown.

View File

@ -21,3 +21,14 @@ type Area struct {
func (e *Entity) AddArea(a Area) {
e.Areas = append(e.Areas, a)
}
func (e *Entity) GetAreaById(areaId string) *Area {
var foundArea *Area
for index, a := range e.Areas {
if a.Id == areaId {
foundArea = &e.Areas[index]
}
}
return foundArea
}

View File

@ -31,3 +31,17 @@ func (collection *DocumentCollection) GetDocumentById(id string) *Entity {
return foundDocument
}
func (collection *DocumentCollection) GetDocumentByAreaId(areaId string) *Entity {
var foundDocument *Entity
for dIndex, d := range collection.Documents {
for _, a := range d.Areas {
if a.Id == areaId {
foundDocument = &collection.Documents[dIndex]
}
}
}
return foundDocument
}

View File

@ -5,35 +5,47 @@ import { PlusIcon, XMarkIcon } from '@heroicons/react/20/solid'
import { ipc } from '../../wailsjs/wailsjs/go/models'
import { useProject } from '../../context/Project/provider'
type NavigationItem = {
type GroupNavigationItem = {
id: string,
name: string,
children: { id: string, name: string }[]
documents: {
id: string,
name: string,
areas: { id: string, name: string }[]
}[]
}
const getNavigationProps = (documents: ipc.Document[], groups: ipc.Group[]): NavigationItem[] => {
const getNavigationProps = (documents: ipc.Document[], groups: ipc.Group[]): GroupNavigationItem[] => {
const groupsWithDocuments = groups.map(g => {
const childrenDocuments = documents
.filter(d => d.groupId === g.id)
.map(d => ({ id: d.id, name: d.name }))
.map(d => ({
id: d.id,
name: d.name,
areas: d.areas.map(a => ({ id: a.id, name: a.name }))
}))
return {
id: g.id,
name: g.name,
children: childrenDocuments
documents: childrenDocuments
}
})
const documentsWithoutGroup = documents
.filter(d => !d.groupId || d.groupId === 'Uncategorized')
.map(d => ({ id: d.id, name: d.name }))
.map(d => ({
id: d.id,
name: d.name,
areas: d.areas.map(a => ({ id: a.id, name: a.name }))
}))
return [
...groupsWithDocuments,
{
id: 'Uncategorized',
name: 'Uncategorized',
children: documentsWithoutGroup
documents: documentsWithoutGroup
}
]
}
@ -44,29 +56,48 @@ function classNames(...classes: any[]) {
function Sidebar() {
const [selectedGroupId, setSelectedGroupId] = useState('')
const [selectedAreaId, setSelectedAreaId] = useState('')
const [isAddNewDocumentInputShowing, setIsAddNewDocumentInputShowing] = useState(false)
const [isAddNewGroupInputShowing, setIsAddNewGroupInputShowing] = useState(false)
const [isEditAreaNameInputShowing, setIsEditAreaNameInputShowing] = useState(false)
const addDocumentTextInput = useRef<HTMLInputElement>(null)
const addGroupTextInput = useRef<HTMLInputElement>(null)
const editAreaNameTextInput = useRef<HTMLInputElement>(null)
const {
documents,
groups,
getAreaById,
requestUpdateArea,
requestAddDocument,
requestAddDocumentGroup,
selectedDocumentId,
setSelectedDocumentId
setSelectedDocumentId,
} = useProject()
const navigation = getNavigationProps(documents, groups)
const getParentGroupIdFromItemId = (itemId: string) => {
let parentGroupId = ''
navigation.forEach(n => {
const foundItem = n.children.find(c => c.id === itemId)
if (foundItem) parentGroupId = n.id
const getGroupIdFromDocumentId = (itemId: string) => {
let groupId = ''
navigation.forEach(g => {
const foundDocument = g.documents.find(d => d.id === itemId)
if (foundDocument) groupId = g.id
})
return parentGroupId
return groupId
}
// const getGroupIdFromAreaId = (areaId: string) => {
// return navigation.find(g => g.documents.map(d => d.areas.map(a => a.id)).flat().includes(areaId))?.id
// }
const getDocumentIdFromAreaId = (areaId: string) => {
let documentId = ''
navigation.map(g => g.documents).flat().forEach(d => {
const doesDocumentIncludeArea = d.areas.map(a => a.id).includes(areaId)
if (doesDocumentIncludeArea) documentId = d.id
})
return documentId
}
const onAddNewDocumentLineItemClickHandler = (groupId: string) => {
@ -80,9 +111,28 @@ function Sidebar() {
setIsAddNewDocumentInputShowing(false)
}
const onItemClickHandler = (itemId: string) => {
const onAreaClick = (areaId: string) => {
getDocumentIdFromAreaId(areaId)
setSelectedDocumentId(getDocumentIdFromAreaId(areaId) || '')
setSelectedAreaId(areaId)
console.log('single click')
}
const onAreaDoubleclick = (areaId: string) => {
const documentIdOfArea = getDocumentIdFromAreaId(areaId)
setIsEditAreaNameInputShowing(true)
// const groupIdOfArea = getGroupIdFromAreaId(areaId)
console.log(documentIdOfArea, selectedDocumentId)
console.log('double click')
}
const onAreaInputBlur = () => {
setIsEditAreaNameInputShowing(false)
}
const onDocumentClickHandler = (itemId: string) => {
setSelectedDocumentId(itemId)
setSelectedGroupId(getParentGroupIdFromItemId(itemId))
setSelectedGroupId(getGroupIdFromDocumentId(itemId))
setIsAddNewDocumentInputShowing(false)
setIsAddNewGroupInputShowing(false)
}
@ -95,6 +145,20 @@ function Sidebar() {
setIsAddNewDocumentInputShowing(false)
}
const onConfirmAreaNameChangeHandler = async (areaDetails: { areaId: string, areaName: string }) => {
console.log(areaDetails)
const { areaId, areaName } = areaDetails
const areaToUpdate = getAreaById(areaId)
if (areaToUpdate) {
areaToUpdate.name = areaName
requestUpdateArea(areaToUpdate)
.then(response => console.log(response))
.catch(console.error)
}
setIsEditAreaNameInputShowing(false)
}
const onConfirmAddDocumentClickHandler = async (groupId: string) => {
const documentName = addDocumentTextInput.current?.value
if (!documentName) return
@ -131,11 +195,11 @@ function Sidebar() {
name="groupName"
id="groupName"
autoFocus
className="text-white placeholder-gray-400 bg-gray-900 bg-opacity-5 block w-full rounded-none rounded-l-md border-late-700 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
className="h-8 text-white placeholder-gray-400 bg-gray-900 bg-opacity-5 block w-full rounded-none rounded-l-md border-late-700 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
placeholder="Add Group"
onKeyDown={(event) => {
onEnterHandler(event,
onConfirmAddGroupClickHandler)
onConfirmAddGroupClickHandler)
}}
ref={addGroupTextInput}
/>
@ -178,12 +242,12 @@ function Sidebar() {
type="text"
name="documentName"
id="documentName"
className="text-white placeholder-gray-400 bg-gray-900 bg-opacity-5 block w-full rounded-none rounded-l-md border-late-700 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
className="h-8 text-white placeholder-gray-400 bg-gray-900 bg-opacity-5 block w-full rounded-none rounded-l-md border-late-700 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
placeholder="Add Document"
autoFocus
onKeyDown={(event) => {
onEnterHandler(event,
() => onConfirmAddDocumentClickHandler(groupId))
() => onConfirmAddDocumentClickHandler(groupId))
}}
ref={addDocumentTextInput}
/>
@ -222,35 +286,81 @@ function Sidebar() {
{renderAddGroupInput()}
{navigation.map((item) =>
<details key={item.name} open={item.id === selectedGroupId}>
{navigation.map((group) =>
<details key={group.name} open={group.id === selectedGroupId}>
<summary className={classNames(
item.id === selectedGroupId
group.id === selectedGroupId
? 'bg-gray-900 text-white'
: 'text-gray-300 hover:bg-gray-700 hover:text-white',
'group items-center px-2 py-2 text-base font-medium rounded-md'
'group items-center px-2 py-2 text-base font-medium rounded-t-md'
)}>
<a role='button'>{item.name}</a>
<a role='button'>{group.name}</a>
</summary>
<ul>
{item.children.map(child => (
<li key={child.id}>
<a
role='button'
onClick={() => onItemClickHandler(child.id)}
className={classNames(
child.id === selectedDocumentId
? 'bg-gray-900 text-white'
: 'text-gray-300 hover:bg-gray-700 hover:text-white',
'group w-full flex items-center pr-2 py-2 text-left font-medium text-sm rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 p-2'
)}
>
{child.name}
</a>
{group.documents.map((d, index) => (
<li className='p-0 m-0' key={d.id}>
<details>
<summary
onClick={() => onDocumentClickHandler(d.id)}
className={classNames(
d.id === selectedDocumentId
? 'bg-gray-900 text-white'
: 'text-gray-300 hover:bg-gray-700 hover:text-white',
'group items-center py-2 text-base font-medium rounded-b-md pl-6',
index !== 0
? 'rounded-t-md'
: ''
)}>
<a
role='button'
className={classNames(
d.id === selectedDocumentId
? 'bg-gray-900 text-white'
: 'text-gray-300 hover:bg-gray-700 hover:text-white',
'text-left font-medium text-sm rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 '
)}
>
{d.name}
</a>
</summary>
<ul>
{d.areas.map((a, index) => (
<li key={a.id}>
{selectedAreaId === a.id && isEditAreaNameInputShowing
? <input
type="text"
name="areaName"
id="areaName"
autoFocus
className="h-8 text-white placeholder-gray-400 bg-gray-900 bg-opacity-5 block w-full rounded-none rounded-l-md border-late-700 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
placeholder={a.name || `Area ${index + 1}`}
onBlur={onAreaInputBlur}
onKeyDown={(event) => {
onEnterHandler(event,
() => onConfirmAreaNameChangeHandler({ areaId: a.id, areaName: event.currentTarget.value }))
}}
ref={editAreaNameTextInput}
/>
: <a
role='button'
onClick={() => onAreaClick(a.id)}
onDoubleClick={() => onAreaDoubleclick(a.id)}
className={classNames('text-gray-300 hover:bg-gray-700 hover:text-white',
'group w-full flex items-center pr-2 py-2 text-left font-medium pl-8 text-xs',
'rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 py-2 select-none'
)}
>
{a.name || `Area ${index + 1}`}
</a>
}
</li>
))}
</ul>
</details>
</li>
))}
{renderAddNewDocument(item.id)}
{renderAddNewDocument(group.id)}
</ul>
</details>
)}

View File

@ -7,7 +7,9 @@ const makeDefaultProject = (): ProjectContextType => ({
groups: [] as ipc.Group[],
selectedDocumentId: '',
getSelectedDocument: () => new ipc.Document(),
getAreaById: (areaId) => undefined,
requestAddArea: (documentId, area) => Promise.resolve(new ipc.Area()),
requestUpdateArea: (updatedArea) => Promise.resolve(new ipc.Area()),
requestAddDocument: (groupId, documentName) => Promise.resolve(new ipc.Document()),
requestAddDocumentGroup: (groupName: string) => Promise.resolve(new ipc.Group()),
setSelectedDocumentId: (id) => {}

View File

@ -1,9 +1,9 @@
'use client'
import { createContext, ReactNode, useContext, useEffect, useState } from 'react'
import { GetDocuments, RequestAddArea, RequestAddDocument, RequestAddDocumentGroup } from '../../wailsjs/wailsjs/go/ipc/Channel'
import { GetDocuments, RequestAddArea, RequestAddDocument, RequestAddDocumentGroup, RequestUpdateArea } from '../../wailsjs/wailsjs/go/ipc/Channel'
import { ipc } from '../../wailsjs/wailsjs/go/models'
import { AddAreaProps, ProjectContextType, ProjectProps } from './types'
import { AddAreaProps, AreaProps, ProjectContextType, ProjectProps } from './types'
import makeDefaultProject from './makeDefaultProject'
const ProjectContext = createContext<ProjectContextType>(makeDefaultProject())
@ -45,6 +45,17 @@ export function ProjectProvider({ children, projectProps }: Props) {
return response
}
const requestUpdateArea = async (updatedArea: AreaProps): Promise<ipc.Area> => {
const response = await RequestUpdateArea(new ipc.Area(updatedArea))
if (response.id) await updateDocuments()
return response
}
const getAreaById = (areaId: string): ipc.Area | undefined => (
documents.map(d => d.areas).flat().find(a => a.id ===areaId)
)
const getSelectedDocument = () => documents.find(d => d.id === selectedDocumentId)
useEffect(() => {
@ -56,9 +67,11 @@ export function ProjectProvider({ children, projectProps }: Props) {
documents,
groups,
getSelectedDocument,
getAreaById,
requestAddArea,
requestAddDocument,
requestAddDocumentGroup,
requestUpdateArea,
selectedDocumentId,
setSelectedDocumentId,
}

View File

@ -14,9 +14,13 @@ export type AddAreaProps = {
endY: number
}
export type AreaProps = { id: string } & AddAreaProps
export type ProjectContextType = {
getSelectedDocument: () => ipc.Document | undefined
getAreaById: (areaId: string) => ipc.Area | undefined
requestAddArea: (documentId: string, area: AddAreaProps) => Promise<ipc.Area>
requestUpdateArea: (area: AreaProps) => Promise<ipc.Area>
requestAddDocument: (groupId: string, documentName: string) => Promise<ipc.Document>
requestAddDocumentGroup: (groupName: string) => Promise<ipc.Group>
selectedDocumentId: string

View File

@ -11,3 +11,5 @@ export function RequestAddArea(arg1:string,arg2:ipc.Area):Promise<ipc.Area>;
export function RequestAddDocument(arg1:string,arg2:string):Promise<ipc.Document>;
export function RequestAddDocumentGroup(arg1:string):Promise<ipc.Group>;
export function RequestUpdateArea(arg1:ipc.Area):Promise<ipc.Area>;

View File

@ -21,3 +21,7 @@ export function RequestAddDocument(arg1, arg2) {
export function RequestAddDocumentGroup(arg1) {
return window['go']['ipc']['Channel']['RequestAddDocumentGroup'](arg1);
}
export function RequestUpdateArea(arg1) {
return window['go']['ipc']['Channel']['RequestUpdateArea'](arg1);
}

View File

@ -161,3 +161,31 @@ func (c *Channel) RequestAddArea(documentId string, area Area) Area {
foundDocument.AddArea(newArea)
return Area(newArea)
}
func (c *Channel) RequestUpdateArea(updatedArea Area) Area {
documentOfArea := document.GetDocumentCollection().GetDocumentByAreaId(updatedArea.Id)
if documentOfArea.Id == "" {
return Area{}
}
areaToUpdate := documentOfArea.GetAreaById((updatedArea.Id))
if areaToUpdate.Id == "" {
return Area{}
}
// TODO: add more prop changes when needed
if updatedArea.Name != "" {
areaToUpdate.Name = updatedArea.Name
}
return Area{
Id: updatedArea.Id,
Name: updatedArea.Name,
StartX: updatedArea.StartX,
StartY: updatedArea.StartY,
EndX: updatedArea.EndX,
EndY: updatedArea.EndY,
}
}