[FWA-5] Update Home List Function

This commit is contained in:
Sam Liu 2024-07-03 08:58:10 +00:00
parent b938f296c1
commit ac841ba8e0
15 changed files with 197 additions and 77 deletions

View File

@ -12,6 +12,7 @@ from backend.core.config import get_app_settings
from backend.db.db_setup import session_context
from backend.repos.repository_users import RepositoryUsers
from backend.repos.seeder import default_users_init
from backend.repos.seeder.init_house import default_house_init
PROJECT_DIR = Path(__file__).parent.parent.parent
@ -20,6 +21,7 @@ logger = root_logger.get_logger()
def init_db(db) -> None:
logger.info("Initializing user data...")
default_users_init(db)
default_house_init(db)
def db_is_at_head(alembic_cfg: config.Config) -> bool:
settings = get_app_settings()

View File

@ -9,13 +9,13 @@ class RepositoryHouses:
self.areas = Areas()
def get_all(self, skip: int = 0, limit: int = 100):
return self.houses.query.filter_by(deleted_at=None).offset(skip).limit(limit).all()
return self.houses.query.filter_by(deleted_at=None).offset(skip*limit).limit(limit).all()
def get_all_areas(self, house_id: str, skip: int = 0, limit: int = 100):
return self.areas.query.filter_by(deleted_at=None, house_id=house_id).offset(skip).limit(limit).all()
def get_count_all(self, skip: int = 0, limit: int = 100):
return self.houses.query.filter_by(deleted_at=None).offset(skip).limit(limit).count()
def get_count_all(self):
return self.houses.query.filter_by(deleted_at=None).count()
def get_by_id(self, house_id: str):
return self.houses.query.filter_by(id=house_id).one()

View File

@ -1 +1,2 @@
from .init_users import default_users_init
from .init_house import default_house_init

View File

@ -0,0 +1,26 @@
from backend.core.config import get_app_settings
from backend.core.root_logger import get_logger
from backend.repos.repository_houses import RepositoryHouses
from sqlalchemy.orm import Session
from backend.schemas.house.house import HouseCreate
logger = get_logger("init_house")
settings = get_app_settings()
def dev_houses() -> list[dict]:
list = []
for x in range(20):
list.append({
"icon": "IconAccessible",
"name": f"Home{x+1}",
"address": f"Address{x+1}",
"areas": [{"name": f"Area{x+1}", "desc": "Description"}],
})
return list
def default_house_init(session: Session):
houses = RepositoryHouses()
for house in dev_houses():
houses.create(session, HouseCreate(**house))

View File

@ -12,19 +12,13 @@ settings = get_app_settings()
def dev_users() -> list[dict]:
return [
{
"username": "sam",
"username": "admin",
"password": "admin",
"name": "Sam",
"is_admin": True,
},
{
"username": "duy",
"password": "admin",
"name": "Duy",
"is_admin": True,
},
{
"username": "sam1",
"username": "admin1",
"password": "admin",
"name": "Sam1",
"is_admin": False,

View File

@ -28,6 +28,6 @@ def create_house(house: HouseCreate, db: db_dependency, current_user: current_us
@public_router.get("/all", response_model=ReturnValue[HousesListResponse])
async def get_all_house(page: int, pageSize: int, current_user: current_user_token) -> ReturnValue[HousesListResponse]:
housesCount = house_service.get_all_count(skip=page-1, limit=pageSize)
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)})

View File

@ -14,4 +14,4 @@ class HouseService(BaseService):
return self.repos.get_all(skip=skip, limit=limit)
def get_all_count(self, skip: int = 0, limit: int = 100):
return self.repos.get_count_all(skip=skip, limit=limit)
return self.repos.get_count_all()

View File

@ -8,8 +8,8 @@ export const postCreateHouse = (payload) => {
export const getAllHouse = ({ page, pageSize }) => {
return protocol.get(
GET_HOUSES_LIST({
page: page(),
pageSize: pageSize(),
page,
pageSize,
}),
{},
)

View File

@ -1,3 +1,4 @@
import ConfirmPopup from '@components/common/ConfirmPopup'
import Popup from '@components/common/Popup'
import TextInput from '@components/common/TextInput'
import Textarea from '@components/common/Textarea'
@ -11,7 +12,7 @@ import {
IconInfoCircle,
IconVector,
} from '@tabler/icons-solidjs'
import { For, Show, createSignal } from 'solid-js'
import { For, Show, createComponent, createSignal } from 'solid-js'
import * as yup from 'yup'
import AreaItem from './AreaItem'
@ -48,10 +49,19 @@ export default function AreaAdd(props) {
setOpenModal(true)
}
const onDeleteAreaItem = (index) => {
const onConfirmDelete = (index) => {
setData((prev) => [...prev.slice(0, index), ...prev.slice(index + 1)])
}
const onClickDeleteItem = (index) => {
createComponent(ConfirmPopup, {
title: language?.message['CONFIRM_DELETE'],
children: language?.message['CONFIRM_DELETE_NOTE'],
deleteId: index,
onConfirm: onConfirmDelete,
})
}
return (
<div class="form-control mb-3">
<div class="join join-vertical">
@ -93,7 +103,7 @@ export default function AreaAdd(props) {
{...item}
formName={props.name}
key={index()}
onDelete={onDeleteAreaItem}
onDelete={onClickDeleteItem}
/>
)}
</For>

View File

@ -1,21 +1,44 @@
import { IconCirclePlus } from '@tabler/icons-solidjs'
import useLanguage from '@hooks/useLanguage'
import { IconAlertTriangle } from '@tabler/icons-solidjs'
import { Show, createSignal } from 'solid-js'
import Popup from '../Popup'
export default function ConfirmPopup(props) {
const [openModal, setOpenModal] = createSignal(true)
const { language } = useLanguage()
const onConfirm = () => {
props.onConfirm(props.deleteId)
setOpenModal(false)
}
return (
<Show when={openModal()}>
<Popup
icon={<IconCirclePlus size={20} class="text-green-500" />}
title="abc"
titleClass="text-lg"
icon={<IconAlertTriangle size={20} class="text-red-500" />}
title={props.title}
titleClass="text-md"
openModal={openModal()}
onModalClose={() => setOpenModal(false)}
class="!w-4/12 !max-w-4xl"
>
<div class="modal-body">{props.children}</div>
<div class="modal-action">
<button
type="submit"
class="btn btn-primary btn-sm"
onClick={onConfirm}
>
{language.ui.confirm}
</button>
<button
type="button"
class="btn btn-ghost btn-sm"
onClick={() => setOpenModal(false)}
>
{language.ui.cancel}
</button>
</div>
</Popup>
</Show>
)

View File

@ -23,6 +23,7 @@ export default function Pagination(props) {
<div class="pagination join">
<button
class="join-item btn btn-sm border border-gray-300"
disabled={localProps.currentPage() === 1}
onClick={onPrevious}
>
«
@ -54,6 +55,10 @@ export default function Pagination(props) {
</For>
<button
class="join-item btn btn-sm border border-gray-300"
disabled={
localProps.currentPage() ===
Math.ceil(localProps.totalCount() / localProps.pageSize())
}
onClick={onNext}
>
»

View File

@ -14,7 +14,7 @@ export const usePagination = ({
siblingCount = 1,
}) => {
const paginationRange = createMemo(() => {
const totalPageCount = Math.ceil(totalCount / pageSize())
const totalPageCount = Math.ceil(totalCount() / pageSize())
const totalPageNumbers = siblingCount + 5

View File

@ -1,4 +1,64 @@
{
"login": "Login",
"logout": "Logout"
"ui": {
"username": "User name",
"password": "Password",
"login": "Login",
"logout": "Logout",
"dashboard": "Dashboard",
"profile": "Profile",
"changeInfo": "Account information",
"save": "Save",
"clear": "Clear",
"house": "Location",
"action": "Action",
"createNew": "Create new",
"location": "Warehouse",
"displayName": "Display name",
"newPassword": "New password",
"confirmNewPassword": "Confirm new password",
"newHouse": "Create new location",
"houseName": "Location name",
"houseIcon": "Icon",
"houseAddress": "Address",
"areas": "Areas",
"areaName": "Area name",
"areaDesc": "Description",
"addArea": "Add area",
"create": "Create",
"update": "Update",
"delete": "Delete",
"confirm": "Confirm",
"cancel": "Cancel",
"findIconHere": "Find icons here",
"empty": "Empty",
"error": "Error!",
"success": "Success!",
"info": "Info",
"loading": "Loading...",
"showing": "Showing"
},
"table": {
"columnName": {
"no": "No.",
"name": "Name",
"icon": "Icon",
"address": "Address",
"action": "Action"
}
},
"message": {
"CREATE_USER_SUCCESS": "Create account successfully!",
"CREATED_USER": "Username is already in use!",
"LOGIN_WRONG": "Wrong username or password.",
"USER_LOCK": "Your account is locked.",
"IS_REQUIRED": "%s is required.",
"PASSWORD_MUSTMATCH": "Password must match.",
"UPDATE_SUCCESS": "Update successfully!",
"UPDATE_PROFILE_SUCCESS": "Update profile successfully!",
"UPDATE_FAIL": "Update failed!",
"API_CALL_FAIL": "API call failed!",
"CREATE_HOUSE_FAIL": "Create new location failed!",
"CREATE_HOUSE_SUCCESS": "Create new location successfully!",
"CONFIRM_DELETE": "Are you sure you want to delete this item?"
}
}

View File

@ -58,6 +58,8 @@
"UPDATE_FAIL": "Cập nhật thất bại!",
"API_CALL_FAIL": "Call API có vẫn đề!",
"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!"
"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."
}
}

View File

@ -1,22 +1,29 @@
import ViewSwitch, { VIEWDATA } from '@components/ViewSwitch'
import useLanguage from '@hooks/useLanguage'
import { IconHome } from '@tabler/icons-solidjs'
import * as icons from '@tabler/icons-solidjs'
import { For, createEffect, createResource, createSignal } from 'solid-js'
import { getAllHouse } from '@api/house'
import Pagination from '@components/common/Pagination'
import { A } from '@solidjs/router'
import {
IconHome2,
IconHomeDot,
IconHome,
IconPencil,
IconSquareRoundedPlus,
IconTrash,
} from '@tabler/icons-solidjs'
import { Dynamic } from 'solid-js/web'
import './house.scss'
const PAGE_SIZE = [10, 50, 100]
const getPaginationText = (total, size, page) => {
const start = (page - 1) * size + 1
const end = Math.min(start + size - 1, total)
return `${start} - ${end} / ${total}`
}
const fetchHouses = async ({ page, pageSize }) => {
const response = await getAllHouse({ page, pageSize })
return response
@ -27,14 +34,17 @@ export default function House() {
const [pageSize, setPageSize] = createSignal(PAGE_SIZE[0])
const [currentPage, setCurrentPage] = createSignal(1)
const [view, setView] = createSignal(VIEWDATA['list'])
const [record, setRecord] = createSignal(null)
const [totalRecord, setTotalRecord] = createSignal(0)
const [houses] = createResource(
{ page: currentPage, pageSize: pageSize },
() => ({ page: currentPage(), pageSize: pageSize() }),
fetchHouses,
)
createEffect(() => {
if (houses()) {
console.log(houses()?.data)
setRecord(houses()?.data?.list)
setTotalRecord(houses()?.data?.total)
}
})
@ -84,56 +94,43 @@ export default function House() {
<div class="col w-4/12">{language.table.columnName.address}</div>
<div class="col w-2/12">{language.table.columnName.action}</div>
</div>
<div class="row view-item">
<div class="col hide w-1/12">1</div>
<div class="col w-1/12">
<IconHome2 size={21} />
</div>
<div class="col w-4/12">Nhà 1</div>
<div class="col w-4/12">Data 4</div>
<div class="col actionbar w-2/12">
<button
class="btn btn-ghost btn-sm px-1 text-blue-500 mr-2"
onClick={onEdit}
>
<IconPencil size={20} />
</button>
<button
class="btn btn-ghost btn-sm px-1 text-red-500"
onClick={onDelete}
>
<IconTrash size={20} />
</button>
</div>
</div>
<div class="row view-item">
<div class="col hide w-1/12">2</div>
<div class="col w-1/12">
<IconHomeDot size={21} />
</div>
<div class="col w-4/12">Nhà 2</div>
<div class="col w-4/12">Data 4</div>
<div class="col actionbar w-2/12">
<button
class="btn btn-ghost btn-sm px-1 text-blue-500 mr-2"
onClick={onEdit}
>
<IconPencil size={20} />
</button>
<button
class="btn btn-ghost btn-sm px-1 text-red-500"
onClick={onDelete}
>
<IconTrash size={20} />
</button>
</div>
</div>
<For each={record()}>
{(item, idx) => (
<div class="row view-item">
<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>
<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}
>
<IconPencil size={20} />
</button>
<button
class="btn btn-ghost btn-sm px-1 text-red-500"
onClick={onDelete}
>
<IconTrash size={20} />
</button>
</div>
</div>
)}
</For>
</div>
</div>
<div class="page-botbar flex max-xs:flex-col justify-between items-center gap-2 mt-5">
<div class="bar-left flex gap-2 justify-start items-center">
<div class="py-2 px-3 border rounded-lg border-gray-300 leading-none">
<span>{language.ui.showing}: 1 - 10 / 100</span>
<span>
{language.ui.showing}:{' '}
{getPaginationText(totalRecord(), pageSize(), currentPage())}
</span>
</div>
<div class="dropdown dropdown-top dropdown-end">
<div
@ -160,7 +157,7 @@ export default function House() {
<div class="bar-right">
<Pagination
currentPage={currentPage}
totalCount={1000}
totalCount={totalRecord}
pageSize={pageSize}
onPageChange={setCurrentPage}
/>