Last Commit for solidjs

This commit is contained in:
Sam Liu 2024-07-24 02:39:55 +00:00
parent 5eb89d3b99
commit 953edb3d0c
18 changed files with 397 additions and 93 deletions

View File

@ -7,3 +7,4 @@ class MessageCode():
REFRESH_TOKEN_EXPIRED: str = 'REFRESH_TOKEN_EXPIRED'
CREATE_HOUSE_FAIL: str = 'CREATE_HOUSE_FAIL'
CREATE_HOUSE_SUCCESS: str = 'CREATE_HOUSE_SUCCESS'
HOUSE_NOT_FOUND: str = 'HOUSE_NOT_FOUND'

View File

@ -30,4 +30,4 @@ class Areas(SqlAlchemyBase, DeleteMixin):
house: Mapped['Houses'] = relationship(back_populates="areas")
def __repr__(self):
return f"{self.__class__.__name__}, name: {self.name}"
return f"<{self.__class__.__name__} id={self.id} name={self.name} house_id={self.house_id}, desc={self.desc}>"

View File

@ -1,7 +1,7 @@
from backend.db.models.houses import Houses, Areas
from sqlalchemy.orm import Session
from backend.schemas.house import HouseCreate
from backend.schemas.house import HouseCreate, HouseUpdate, AreaUpdate
class RepositoryHouses:
def __init__(self):
@ -34,3 +34,45 @@ class RepositoryHouses:
db.refresh(db_house)
return db_house
def update_area(self, db: Session, areas: list[AreaUpdate], house_id: str):
db_house = self.get_by_id(house_id)
if not db_house:
return None
try:
db_areaId = [area.id for area in db_house.areas]
area_update_id = [area.id for area in areas if area.id is not None]
area_delete_id = [area_id for area_id in db_areaId if area_id not in area_update_id]
if area_delete_id:
self.areas.query.where(Areas.id.in_(area_delete_id)).delete()
for area in areas:
area_obj = Areas(**area.dict(), house_id=house_id)
db.merge(area_obj)
# areaList = [dict(**area.dict(), house_id=house_id) for area in areas]
# db.execute(update(Areas), areaList)
# self.areas.query.update(areaList)
db.commit()
except Exception:
db.rollback()
raise
def update(self, db: Session, house: HouseUpdate):
db_house = self.get_by_id(house.id)
if not db_house:
return None
try:
self.houses.query.where(Houses.id == house.id).update(house.dict(exclude={"id", 'areas'}, exclude_unset=True, exclude_none=True))
db.commit()
self.update_area(db, house.areas, house.id)
except Exception:
db.rollback()
raise
db.refresh(db_house)
return db_house
def delete(self, db: Session, house_id: str):
pass

View File

@ -7,7 +7,7 @@ from backend.core.message_code import MessageCode
from backend.db.db_setup import generate_session
from backend.schemas.common import ReturnValue
from backend.schemas.house import HouseCreate
from backend.schemas.house.house import HousesListResponse
from backend.schemas.house.house import HouseUpdate, HousesListResponse, HouseResponse
from backend.schemas.user import ProfileResponse
from backend.services.house import HouseService
@ -27,7 +27,19 @@ def create_house(house: HouseCreate, db: db_dependency, current_user: current_us
return ReturnValue(status=200, data=MessageCode.CREATE_HOUSE_SUCCESS)
@public_router.get("/all", response_model=ReturnValue[HousesListResponse])
async def get_all_house(page: int, pageSize: int, current_user: current_user_token) -> ReturnValue[HousesListResponse]:
def get_all_house(page: int, pageSize: int, current_user: current_user_token) -> ReturnValue[HousesListResponse]:
housesCount = house_service.get_all_count()
houses = house_service.get_all(skip=page-1, limit=pageSize)
return ReturnValue(status=200, data={'total': housesCount, 'list': list(houses)})
@public_router.get("/{house_id}", response_model=ReturnValue[HouseResponse])
def get_house_by_id(house_id: str, current_user: current_user_token) -> ReturnValue[HouseCreate]:
house = house_service.get_by_id(id=house_id)
if not house:
raise HTTPException(status_code=404, detail=MessageCode.HOUSE_NOT_FOUND)
return ReturnValue(status=200, data=house)
@public_router.put("/update", response_model=ReturnValue[HouseCreate])
def update_house(house: HouseUpdate, current_user: current_user_token, db: db_dependency) -> ReturnValue[Any]:
db_house = house_service.update(db=db, house=house)
return ReturnValue(status=200, data=db_house)

View File

@ -5,23 +5,33 @@ from pydantic import ConfigDict
from backend.schemas.main_model import MainModel
class HouseBase(MainModel):
pass
class AreaBase(MainModel):
pass
class AreaCreate(AreaBase):
name: str
desc: str
class HouseCreate(HouseBase):
icon: str
name: str
address: str
areas: list[AreaCreate]
class AreaBase(MainModel):
name: str
desc: str
class AreaUpdate(AreaBase):
id: UUID | None = None
model_config = ConfigDict(from_attributes=True)
class HousesList(HouseCreate):
class HouseCreate(HouseBase):
areas: list[AreaBase]
model_config = ConfigDict(from_attributes=True)
class HouseUpdate(HouseBase):
id: UUID
areas: list[AreaUpdate]
model_config = ConfigDict(from_attributes=True)
class HouseResponse(HouseBase):
id: UUID
areas: list[AreaUpdate]
model_config = ConfigDict(from_attributes=True)
class HousesList(HouseBase):
id: UUID
created_at: datetime
updated_at: datetime

View File

@ -1,6 +1,6 @@
from sqlalchemy.orm import Session
from backend.repos import RepositoryHouses
from backend.schemas import HouseCreate
from backend.schemas import HouseCreate, HouseUpdate
from backend.services._base_service import BaseService
class HouseService(BaseService):
@ -13,5 +13,11 @@ class HouseService(BaseService):
def get_all(self, skip: int = 0, limit: int = 100):
return self.repos.get_all(skip=skip, limit=limit)
def get_all_count(self, skip: int = 0, limit: int = 100):
def get_all_count(self):
return self.repos.get_count_all()
def get_by_id(self, id: str):
return self.repos.get_by_id(house_id=id)
def update(self, db: Session, house: HouseUpdate):
return self.repos.update(db=db, house=house)

View File

@ -26,6 +26,7 @@
"crypto-js": "^4.2.0",
"solid-js": "^1.8.15",
"solid-toast": "^0.5.0",
"uuid": "^10.0.0",
"yup": "^1.4.0"
},
"devDependencies": {

View File

@ -41,6 +41,9 @@ importers:
solid-toast:
specifier: ^0.5.0
version: 0.5.0(solid-js@1.8.17)
uuid:
specifier: ^10.0.0
version: 10.0.0
yup:
specifier: ^1.4.0
version: 1.4.0
@ -1668,6 +1671,10 @@ packages:
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
uuid@10.0.0:
resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
hasBin: true
validate-html-nesting@1.2.2:
resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==}
@ -3302,6 +3309,8 @@ snapshots:
util-deprecate@1.0.2: {}
uuid@10.0.0: {}
validate-html-nesting@1.2.2: {}
vite-plugin-mkcert@1.17.5(vite@5.2.11(sass@1.77.4)):

View File

@ -1,5 +1,10 @@
import { protocol } from './index'
import { GET_HOUSES_LIST, POST_HOUSE_CREATE } from './url'
import {
GET_HOUSE_DETAIL,
GET_HOUSES_LIST,
POST_HOUSE_CREATE,
PUT_UPDATE_HOUSE,
} from './url'
export const postCreateHouse = (payload) => {
return protocol.post(POST_HOUSE_CREATE, payload)
@ -14,3 +19,11 @@ export const getAllHouse = ({ page, pageSize }) => {
{},
)
}
export const getHouseDetail = (id) => {
return protocol.get(GET_HOUSE_DETAIL(id), {})
}
export const putUpdateHouse = (payload) => {
return protocol.put(PUT_UPDATE_HOUSE, payload)
}

View File

@ -3,6 +3,12 @@ export const POST_LOGOUT = '/api/auth/logout'
export const POST_REFRESH = '/api/auth/refresh'
export const GET_USER_PROFILE = '/api/user/me'
export const PUT_UPDATE_USER_PROFILE = '/api/user/update-profile'
/**
* House API
*/
export const POST_HOUSE_CREATE = '/api/house/create'
export const GET_HOUSES_LIST = ({ page, pageSize }) =>
`/api/house/all?page=${page}&pageSize=${pageSize}`
export const GET_HOUSE_DETAIL = (id) => `/api/house/${id}`
export const PUT_UPDATE_HOUSE = '/api/house/update'

View File

@ -8,11 +8,20 @@ import useLanguage from '@hooks/useLanguage'
import {
IconAddressBook,
IconCirclePlus,
IconEditCircle,
IconFileDescription,
IconInfoCircle,
IconVector,
} from '@tabler/icons-solidjs'
import { For, Show, createComponent, createSignal } from 'solid-js'
import {
createComponent,
createEffect,
createSignal,
For,
Show,
untrack,
} from 'solid-js'
import { v4 as uuidv4 } from 'uuid'
import * as yup from 'yup'
import AreaItem from './AreaItem'
@ -25,39 +34,85 @@ import AreaItem from './AreaItem'
*/
const areaSchema = (language, isRequired) =>
yup.object({
name: yup.string().required(isRequired(language.ui.areaName)),
description: yup.string().required(isRequired(language.ui.areaName)),
name: yup
.string()
.min(3, language.message['MIN_THREE_CHAR'])
.required(isRequired(language.ui.areaName)),
desc: yup
.string()
.min(3, language.message['MIN_THREE_CHAR'])
.required(isRequired(language.ui.areaName)),
})
export default function AreaAdd(props) {
const [openModal, setOpenModal] = createSignal(false)
const [data, setData] = createSignal([])
const [dataArea, setDataArea] = createSignal([])
const [editMode, setEditMode] = createSignal(false)
const { language, isRequired } = useLanguage()
const { form, reset, errors } = createForm({
extend: [validator({ schema: areaSchema(language, isRequired) })],
onSubmit: async (values) => {
setData((prev) => [...prev, values])
onModalClose()
},
const { form, reset, data, setData, errors, createSubmitHandler } =
createForm({
extend: [validator({ schema: areaSchema(language, isRequired) })],
onSubmit: async (values) => {
values.id = uuidv4()
values.isCreate = true
setDataArea((prev) => [...prev, values])
onModalClose()
},
})
createEffect(() => {
if (props.value && dataArea().length === 0) {
console.log(props.value)
untrack(() => setDataArea(props.value))
}
})
const onModalClose = () => {
setOpenModal(false), reset()
setOpenModal(false), reset(), setEditMode(false)
}
const onOpenModal = () => {
setOpenModal(true)
}
const onConfirmDelete = (index) => {
setData((prev) => [...prev.slice(0, index), ...prev.slice(index + 1)])
const onConfirmDelete = (delId) => {
setDataArea((prev) => {
prev = prev.filter((item) => item.id !== delId)
return [...prev]
})
props.setData('areas', dataArea())
}
const onClickDeleteItem = (index) => {
const onClickEditItem = (id) => {
const editItem = dataArea().find((item) => item.id === id)
setData(editItem)
setEditMode(true)
setOpenModal(true)
}
const onClickUpdateItem = createSubmitHandler({
onSubmit: (values) => {
setDataArea((prev) => {
prev = prev.map((item) => {
if (item.id === values.id) {
return values
}
return item
})
return [...prev]
})
props.setData('areas', dataArea())
reset()
setEditMode(false)
onModalClose()
},
})
const onClickDeleteItem = (delId) => {
createComponent(ConfirmPopup, {
title: language?.message['CONFIRM_DELETE'],
children: language?.message['CONFIRM_DELETE_NOTE'],
deleteId: index,
deleteId: delId,
onConfirm: onConfirmDelete,
})
}
@ -96,14 +151,15 @@ export default function AreaAdd(props) {
classList={{ 'border-red-500': props.error }}
>
<div class="p-3 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<Show when={data().length > 0} fallback={language.ui.empty}>
<For each={data()}>
<Show when={dataArea().length > 0} fallback={language.ui.empty}>
<For each={dataArea()}>
{(item, index) => (
<AreaItem
{...item}
data={item}
formName={props.name}
key={index()}
num={index()}
onDelete={onClickDeleteItem}
onEdit={onClickEditItem}
/>
)}
</For>
@ -112,8 +168,14 @@ export default function AreaAdd(props) {
</div>
</div>
<Popup
icon={<IconCirclePlus size={20} class="text-green-500" />}
title={language.ui.addArea}
icon={
editMode() ? (
<IconEditCircle size={20} class="text-blue-500" />
) : (
<IconCirclePlus size={20} class="text-green-500" />
)
}
title={editMode() ? language.ui.editArea : language.ui.addArea}
titleClass="text-lg"
openModal={openModal()}
onModalClose={onModalClose}
@ -126,20 +188,35 @@ export default function AreaAdd(props) {
name="name"
label={language.ui.areaName}
placeholder={language.ui.areaName}
value={data('name')}
error={errors('name')}
/>
<Textarea
icon={IconFileDescription}
name="description"
name="desc"
label={language.ui.areaDesc}
placeholder={language.ui.areaDesc}
error={errors('description')}
value={data('desc')}
error={errors('desc')}
/>
</div>
<div class="modal-action">
<button type="submit" class="btn btn-primary">
{language.ui.save}
</button>
<Show
when={editMode()}
fallback={
<button type="submit" class="btn btn-primary">
{language.ui.save}
</button>
}
>
<button
type="submit"
class="btn btn-primary"
onClick={onClickUpdateItem}
>
{language.ui.update}
</button>
</Show>
<button type="button" class="btn btn-ghost" onClick={onModalClose}>
{language.ui.cancel}
</button>

View File

@ -1,32 +1,54 @@
import { IconTrash } from '@tabler/icons-solidjs'
import { IconPencil, IconTrash } from '@tabler/icons-solidjs'
import { Show } from 'solid-js'
export default function AreaItem(props) {
const data = () => props.data
return (
<div class="flex justify-between items-center shadow rounded-lg p-3 border border-gray-300">
<div class="">
<span class="text-md font-bold">{props.name}</span>
<p class="text-xs">{props.description}</p>
<div class="flex justify-between shadow rounded-lg p-3 border border-gray-300">
<div class="item-body">
<span class="text-md font-bold">{data().name}</span>
<p class="text-xs">{data().desc}</p>
<Show when={!data().isCreate}>
<input
type="hidden"
name={`${props.formName}.${props.num}.id`}
value={data().id}
/>
</Show>
<input
type="hidden"
name={`${props.formName}.${props.key}.name`}
value={props.name}
name={`${props.formName}.${props.num}.name`}
value={data().name}
data-value={data().name}
/>
<input
type="hidden"
name={`${props.formName}.${props.key}.desc`}
value={props.description}
name={`${props.formName}.${props.num}.desc`}
value={data().desc}
data-value={data().desc}
/>
</div>
<Show when={props.onDelete}>
<button
type="button"
class="btn btn-circle btn-ghost btn-sm text-red-500 hover:bg-red-100"
onClick={() => props.onDelete(props.key)}
>
<IconTrash size={20} />
</button>
</Show>
<div class="flex">
<Show when={props.onEdit}>
<button
type="button"
class="btn btn-circle btn-ghost btn-sm text-blue-500 hover:bg-blue-100"
onClick={() => props.onEdit(data().id)}
>
<IconPencil size={20} />
</button>
</Show>
<Show when={props.onDelete}>
<button
type="button"
class="btn btn-circle btn-ghost btn-sm text-red-500 hover:bg-red-100"
onClick={() => props.onDelete(data().id)}
>
<IconTrash size={20} />
</button>
</Show>
</div>
</div>
)
}

View File

@ -17,6 +17,7 @@
"newPassword": "Mật khẩu mới",
"confirmNewPassword": "Nhập lại mật khẩu",
"newHouse": "Tạo địa điểm mới",
"editHouse": "Sửa địa điểm",
"houseName": "Tên địa điểm",
"houseIcon": "Ký tự",
"houseAddress": "Địa chỉ",
@ -24,6 +25,7 @@
"areaName": "Tên khu vực",
"areaDesc": "Mô tả",
"addArea": "Thêm khu vực",
"editArea": "Sửa khu vực",
"create": "Tạo",
"update": "Cập nhật",
"delete": "Xóa",
@ -60,6 +62,7 @@
"CREATE_HOUSE_FAIL": "Tạo địa điểm mới thất bại!",
"CREATE_HOUSE_SUCCESS": "Tạo địa điểm mới thành công!",
"CONFIRM_DELETE": "Bạn có chắc là muốn xóa mục này?",
"CONFIRM_DELETE_NOTE": "Chú Ý ‼: Một khi đã XÓA thì không thể nào khôi phục lại được."
"CONFIRM_DELETE_NOTE": "Chú Ý ‼: Một khi đã XÓA thì không thể nào khôi phục lại được.",
"MIN_THREE_CHAR": "Ít nhất phải có 3 ký tự"
}
}

View File

@ -1,17 +1,25 @@
import ViewSwitch, { VIEWDATA } from '@components/ViewSwitch'
import useLanguage from '@hooks/useLanguage'
import * as icons from '@tabler/icons-solidjs'
import { For, createEffect, createResource, createSignal } from 'solid-js'
import {
For,
createComponent,
createEffect,
createResource,
createSignal,
} from 'solid-js'
import { getAllHouse } from '@api/house'
import ConfirmPopup from '@components/common/ConfirmPopup'
import Pagination from '@components/common/Pagination'
import { A } from '@solidjs/router'
import { A, useNavigate } from '@solidjs/router'
import {
IconHome,
IconPencil,
IconSquareRoundedPlus,
IconTrash,
} from '@tabler/icons-solidjs'
import { Helpers } from '@utils/helper'
import { Dynamic } from 'solid-js/web'
import './house.scss'
@ -31,6 +39,7 @@ const fetchHouses = async ({ page, pageSize }) => {
export default function House() {
const { language } = useLanguage()
const navigate = useNavigate()
const [pageSize, setPageSize] = createSignal(PAGE_SIZE[0])
const [currentPage, setCurrentPage] = createSignal(1)
const [view, setView] = createSignal(VIEWDATA['list'])
@ -48,12 +57,23 @@ export default function House() {
}
})
const onEdit = () => {
console.log('edit')
const onClickEdit = (editId) => {
navigate(Helpers.getRoutePath('edit-location').replace(':id', editId), {
replace: true,
})
}
const onDelete = () => {
console.log('delete')
const onConfirmDelete = (deleteId) => {
console.log(deleteId)
}
const onClickDelete = (deleteId) => {
createComponent(ConfirmPopup, {
title: language?.message['CONFIRM_DELETE'],
children: language?.message['CONFIRM_DELETE_NOTE'],
deleteId,
onConfirm: onConfirmDelete,
})
}
const onSetPageSize = (pageSize) => {
@ -100,21 +120,21 @@ export default function House() {
<div class="col hide w-1/12">
{pageSize() * currentPage() - (pageSize() - idx() - 1)}
</div>
<div class="col w-1/12">
<Dynamic component={icons[item?.icon]} size={21} />
<div class="col symbol w-1/12">
<Dynamic component={icons[item?.icon]} class="w-7 h-7" />
</div>
<div class="col w-4/12">{item?.name}</div>
<div class="col w-4/12">{item?.address}</div>
<div class="col actionbar w-2/12">
<button
class="btn btn-ghost btn-sm px-1 text-blue-500 mr-2"
onClick={onEdit}
class="btn btn-ghost btn-sm px-1 text-blue-500"
onClick={[onClickEdit, item?.id]}
>
<IconPencil size={20} />
</button>
<button
class="btn btn-ghost btn-sm px-1 text-red-500"
onClick={onDelete}
onClick={[onClickDelete, item?.id]}
>
<IconTrash size={20} />
</button>
@ -144,7 +164,7 @@ export default function House() {
tabindex="0"
class="dropdown-content menu bg-base-100 rounded-box z-[1] w-32 p-2 shadow mb-2"
>
<For each={PAGE_SIZE.reverse()}>
<For each={PAGE_SIZE}>
{(pageSize) => (
<li>
<a onClick={[onSetPageSize, pageSize]}>{pageSize}</a>

View File

@ -12,6 +12,10 @@
&.view-head {
@apply bg-base-200 font-bold;
}
& > .actionbar {
@apply flex gap-2;
}
}
}
@ -24,10 +28,11 @@
& .row {
&.view-item {
@apply card bg-base-100 shadow-md border border-gray-200 p-3 relative pb-8;
@apply card bg-base-100 shadow-md border border-gray-200 relative
grid grid-rows-2 grid-flow-col p-2 pr-4 gap-1 auto-cols-max overflow-hidden;
& .col {
@apply w-auto
@apply w-auto;
}
& > .hide {
@ -35,10 +40,23 @@
visibility: hidden;
}
& .col.symbol {
@apply row-span-2 border-r border-gray-300 bg-white flex items-center pr-2 mr-2;
& > svg {
@apply w-14 h-14;
}
}
& > .actionbar {
@apply absolute right-0 bottom-0 flex px-3 py-1 w-auto border-t border-l rounded-tl-xl;
@apply absolute flex flex-col justify-center px-3 w-auto h-full border-l rounded-xl bg-white z-10 transition-all;
right: -45px;
box-shadow: -1px -1px 10px 0px rgba(0,0,0,0.1);
}
&:hover > .actionbar {
@apply right-0;
}
}
&.view-head {

View File

@ -1,40 +1,77 @@
import { postCreateHouse } from '@api/house'
import { getHouseDetail, postCreateHouse, putUpdateHouse } from '@api/house'
import AreaAdd from '@components/AreaAdd'
import TextInput from '@components/common/TextInput'
import { createForm } from '@felte/solid'
import { validator } from '@felte/validator-yup'
import useLanguage from '@hooks/useLanguage'
import useToast from '@hooks/useToast'
import { A, useNavigate } from '@solidjs/router'
import { A, useNavigate, useParams } from '@solidjs/router'
import {
IconAddressBook,
IconIcons,
IconLocationBolt,
IconMapPinPlus,
IconTag,
} from '@tabler/icons-solidjs'
import { Helpers } from '@utils/helper'
import { createEffect, createResource, Show } from 'solid-js'
import * as yup from 'yup'
const houseSchema = (language, isRequired) =>
yup.object({
icon: yup.string().required(isRequired(language.ui.houseIcon)),
name: yup.string().required(isRequired(language.ui.houseName)),
address: yup.string().required(isRequired(language.ui.houseAddress)),
icon: yup
.string()
.min(3, language.message['MIN_THREE_CHAR'])
.required(isRequired(language.ui.houseIcon)),
name: yup
.string()
.min(3, language.message['MIN_THREE_CHAR'])
.required(isRequired(language.ui.houseName)),
address: yup
.string()
.min(3, language.message['MIN_THREE_CHAR'])
.required(isRequired(language.ui.houseAddress)),
areas: yup
.array()
.min(1, isRequired(language.ui.areas))
.required(isRequired(language.ui.areas)),
})
const fetchHouses = async (id) => {
if (id) {
const response = await getHouseDetail(id)
if (response.status === 200) {
return response.data
}
return response
}
return null
}
export default function HouseCreate() {
const { language, isRequired } = useLanguage()
const notify = useToast()
const navigate = useNavigate()
const { form, errors } = createForm({
const { id } = useParams()
const [house] = createResource(id, fetchHouses)
const { form, data, setData, errors } = createForm({
extend: [validator({ schema: houseSchema(language, isRequired) })],
onSubmit: async (values) => {
console.log(values)
const resp = await postCreateHouse(values)
const call = id ? putUpdateHouse : postCreateHouse
const result = {
...values,
areas: values.areas.map((item) =>
id
? { ...item }
: {
name: item.name,
desc: item.desc,
},
),
}
console.log(values.areas)
const resp = await call(result)
return resp
},
onSuccess: (resp) => {
@ -45,7 +82,7 @@ export default function HouseCreate() {
language.message[resp.data] ||
language.message['CREATE_HOUSE_SUCCESS'],
})
navigate(Helpers.getRoutePath('location'), { replace: true })
// navigate(Helpers.getRoutePath('location'), { replace: true })
}
},
onError: (error) => {
@ -58,6 +95,12 @@ export default function HouseCreate() {
},
})
createEffect(() => {
if (id && house()) {
setData(house())
}
})
return (
<div class="house-create">
<div class="text-sm breadcrumbs mb-2">
@ -65,18 +108,21 @@ export default function HouseCreate() {
<li>
<A href={Helpers.getRoutePath('location')}>{language.ui.house}</A>
</li>
<li>{language.ui.newHouse}</li>
<li>{id ? language.ui.editHouse : language.ui.newHouse}</li>
</ul>
</div>
<div class="flex items-center gap-2 mb-5 text-xl">
<span class="text-secondary">
<IconMapPinPlus size={30} />
{id ? <IconLocationBolt size={30} /> : <IconMapPinPlus size={30} />}
</span>
{language.ui.newHouse}
{id ? language.ui.editHouse : language.ui.newHouse}
</div>
<div class="card w-full bg-base-100 shadow-lg border border-gray-200">
<div class="card-body">
<form autoComplete="off" use:form>
<Show when={id}>
<input type="hidden" name="id" value={id} />
</Show>
<div class="grid gap-4 grid-cols-1 lg:grid-cols-2">
<div class="col-auto">
<TextInput
@ -85,6 +131,7 @@ export default function HouseCreate() {
label={language.ui.houseIcon}
labelClass="md:w-40"
placeholder={language.ui.houseIcon}
value={data('icon')}
error={errors('icon')}
>
<div class="label">
@ -105,6 +152,7 @@ export default function HouseCreate() {
label={language.ui.houseName}
labelClass="md:w-40"
placeholder={language.ui.houseName}
value={data('name')}
error={errors('name')}
/>
</div>
@ -115,12 +163,15 @@ export default function HouseCreate() {
label={language.ui.houseAddress}
labelClass="md:w-40"
placeholder={language.ui.houseAddress}
value={data('address')}
error={errors('address')}
/>
</div>
<div class="col-auto lg:col-span-2">
<AreaAdd
name="areas"
value={data('areas')}
setData={setData}
error={
errors('areas') &&
Helpers.clearArrayWithNullObject(errors('areas'))
@ -130,8 +181,11 @@ export default function HouseCreate() {
</div>
<div class="card-actions">
<button type="submit" class="btn btn-primary">
{language.ui.create}
{id ? language.ui.update : language.ui.create}
</button>
<A href={Helpers.getRoutePath('location')} class="btn btn-ghost">
{language.ui.cancel}
</A>
</div>
</form>
</div>

View File

@ -36,6 +36,15 @@ export const ROUTES = [
filter: {},
show: true,
},
{
name: 'edit-location',
path: '/location/edit/:id',
components: lazy(() => import('@pages/HouseCreate')),
filter: {
id: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/,
},
show: true,
},
{
name: 'warehouse',
path: '/warehouse',

View File

@ -31,7 +31,7 @@ export default defineConfig(({ mode }) => {
plugins: [solid()],
server: {
https: false,
host: true,
host: false,
port: 5001,
strictPort: true,
watch: {
@ -59,6 +59,7 @@ export default defineConfig(({ mode }) => {
// plugins: [solid(), mkcert()],
plugins: [solid()],
server: {
open: true,
https: false,
host: true,
port: 5001,