Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import OrderGridWithPagination from '@/components/OrderGrid/OrderGridWithPagination';
import type { OrderGridQueryParams } from '@/components/OrderGrid/order-grid.query';
import Header from '@/components/Header';

type HomeProps = {
searchParams: Promise<{
page?: string;
}>;
searchParams: Promise<OrderGridQueryParams>;
};

export default async function Home({ searchParams }: HomeProps) {
return (
<div className="page-container">
<Header />
<main className="main">
<h1>Gerenciamento de ordens</h1>
<h2>Gerenciamento de ordens</h2>
<OrderGridWithPagination searchParams={searchParams} />
</main>
</div>
Expand Down
168 changes: 167 additions & 1 deletion components/OrderGrid/OrderGrid.styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,26 @@
@apply font-semibold bg-black text-white;
}

.orders-grid__sort-link {
@apply inline-flex w-full items-center justify-between gap-2 text-white no-underline;
}

.orders-grid__sort-link--active {
@apply font-semibold;
}

.orders-grid__sort-indicator {
@apply text-grid-xm;
Comment on lines +38 to +47

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Biome config files =="
fd -HI 'biome\.jsonc?$' .

CONFIG="$(fd -HI 'biome\.jsonc?$' . | head -n1 || true)"
if [ -n "${CONFIG:-}" ]; then
  echo
  echo "== Tailwind-related parser settings in ${CONFIG} =="
  rg -n -C2 'tailwindDirectives|css|parser' "$CONFIG" || true
else
  echo "No biome.json/biome.jsonc found."
fi

echo
echo "== Tailwind `@apply` usage in components/OrderGrid/OrderGrid.styles.css =="
rg -n -C1 '@apply' components/OrderGrid/OrderGrid.styles.css

Repository: atelesjr/base-orders

Length of output: 3036


Enable Tailwind directives in Biome config to stop parse failures on these CSS rules.

The Biome CSS parser is not configured to support Tailwind's @apply directive. Add "tailwindDirectives": true to the css.parser settings in biome.json to resolve parse errors being reported across lines 39, 43, 47, 79, 83, 87, 95, and 125 (30+ uses of @apply throughout this file).

🧰 Tools
🪛 Biome (2.4.6)

[error] 39-39: Tailwind-specific syntax is disabled.

(parse)


[error] 43-43: Tailwind-specific syntax is disabled.

(parse)


[error] 47-47: Tailwind-specific syntax is disabled.

(parse)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/OrderGrid/OrderGrid.styles.css` around lines 38 - 47, The Biome
CSS parser is failing on Tailwind `@apply` usages (e.g., selectors
.orders-grid__sort-link, .orders-grid__sort-link--active,
.orders-grid__sort-indicator) because Tailwind directives are not enabled; open
your biome.json and under the css.parser settings add "tailwindDirectives": true
to enable parsing of `@apply` and other Tailwind directives, then re-run the
linter/formatter to confirm the parse errors across the OrdersGrid stylesheet
are resolved.

}

.orders-grid__td {
@apply text-grid-xm;
}

.orders-grid__empty-state {
@apply px-4 py-6 text-center text-grid-sm text-black;
}

.orders-grid__row:last-child {
@apply border-b-0;
}
Expand All @@ -63,14 +79,152 @@
@apply mt-4 flex items-center justify-end gap-3;
}

.orders-grid__toolbar {
@apply mb-3 flex items-center justify-between gap-4;
}

.orders-grid__actions {
@apply flex items-center gap-4;
}

.orders-grid__action-button {
@apply inline-flex cursor-pointer items-center justify-center gap-1 border-0 bg-transparent p-0 text-grid-sm text-black transition-opacity hover:opacity-80;
}

.orders-grid__action-button--active {
@apply font-semibold;
}

.orders-grid__action-label {
@apply whitespace-nowrap;
}

.orders-grid__pagination--top {
@apply mt-0 mb-3;
@apply mt-0 mb-0;
}

.orders-grid__pagination--bottom {
@apply mt-4;
}

.orders-grid__filters {
@apply mb-4 rounded-lg border border-black bg-gray-light p-4;
}

.orders-grid__filters-grid {
@apply grid grid-cols-1 gap-3 md:grid-cols-2 xl:grid-cols-5;
}

.orders-grid__filter-field {
@apply flex flex-col gap-1 text-grid-sm text-black;
}

.orders-grid__filter-field input,
.orders-grid__filter-field select {
@apply h-9 rounded border border-black bg-white px-2 text-grid-sm;
}

.orders-grid__filter-select {
@apply relative;
}

.orders-grid__filter-select-trigger {
@apply h-9 w-full rounded border border-black bg-white px-2 text-left text-grid-sm text-black inline-flex items-center justify-between;
}

.orders-grid__filter-select-menu {
@apply absolute left-0 top-full z-20 mt-1 w-full overflow-hidden rounded border border-black bg-white;
}

.orders-grid__filter-select-option {
@apply w-full px-2 py-1 text-left text-grid-sm text-black;
}

.orders-grid__filter-select-option:hover {
@apply bg-green;
}

.orders-grid__filter-select-option:active {
@apply bg-green-dark text-white;
}

.orders-grid__filter-select-option--selected {
@apply font-semibold;
}

.orders-grid__date-picker {
@apply relative;
}

.orders-grid__date-picker-trigger {
@apply h-9 w-full rounded border border-black bg-white px-2 text-left text-grid-sm text-black inline-flex items-center justify-between leading-none;
}

.orders-grid__date-picker-popover {
@apply absolute right-0 top-full z-20 mt-1 w-[320px] max-w-[calc(100vw-2rem)] rounded border border-black bg-white p-3 shadow-md;
}

.orders-grid__date-picker-header {
@apply mb-2 flex items-center justify-between text-grid-sm;
}

.orders-grid__date-picker-nav {
@apply flex items-center gap-1;
}

.orders-grid__date-picker-nav button {
@apply h-7 w-7 rounded text-grid-sm hover:bg-green active:bg-green-dark;
}

.orders-grid__date-picker-weekdays {
@apply mb-1 grid grid-cols-7 text-center text-grid-sm font-semibold;
}

.orders-grid__date-picker-grid {
@apply grid grid-cols-7 gap-1;
}

.orders-grid__date-picker-day {
@apply h-8 rounded text-grid-sm hover:bg-green active:bg-green-dark;
}

.orders-grid__date-picker-day--outside {
@apply text-black/40;
}

.orders-grid__date-picker-day--today {
@apply border border-black;
}

.orders-grid__date-picker-day--selected {
@apply bg-green font-semibold;
}

.orders-grid__date-picker-actions {
@apply mt-2 flex items-center justify-between;
}

.orders-grid__date-picker-actions button {
@apply rounded px-2 py-1 text-grid-sm hover:bg-green active:bg-green-dark;
}

.orders-grid__filters-actions {
@apply mt-3 flex items-center justify-end gap-2;
}

.orders-grid__filter-submit,
.orders-grid__filter-clear {
@apply inline-flex h-9 items-center justify-center rounded border border-black px-3 text-grid-sm transition-opacity hover:opacity-80;
}

.orders-grid__filter-submit {
@apply bg-black text-white;
}

.orders-grid__filter-clear {
@apply bg-white text-black;
}

.orders-grid__page-button {
@apply inline-flex items-center justify-center rounded-full transition-transform hover:scale-105;
}
Expand All @@ -92,4 +246,16 @@
.orders-grid__pagination {
@apply justify-center;
}

.orders-grid__toolbar {
@apply flex-wrap;
}

.orders-grid__filters-actions {
@apply justify-start;
}

.orders-grid__date-picker-popover {
@apply right-auto left-0 w-[min(320px,calc(100vw-2rem))];
}
}
35 changes: 15 additions & 20 deletions components/OrderGrid/OrderGridWithPagination.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,30 @@
import { getPaginatedOrdersForGrid } from '@/lib/orders/orders.service';
import OrderGridWithPaginationClient from './OrderGridWithPaginationClient';
import {
buildOrderGridWithPaginationViewModel,
} from './order-grid-with-pagination.presenter';
import { type OrderGridQueryParams } from './order-grid.query';

type OrderGridWithPaginationProps = {
searchParams: Promise<{
page?: string;
}>;
searchParams: Promise<OrderGridQueryParams>;
pageSize?: number;
};

const OrderGridWithPagination = async ({
searchParams,
pageSize = 15,
}: OrderGridWithPaginationProps) => {
const resolvedSearchParams = await searchParams;
const parsedPage = Number.parseInt(resolvedSearchParams.page ?? '1', 10);
const requestedPage = Number.isNaN(parsedPage)
? 1
: Math.max(1, parsedPage);

const { items, currentPage, totalPages, prevPage, nextPage } =
await getPaginatedOrdersForGrid(requestedPage, pageSize);

const pagination = {
currentPage,
totalPages,
prevHref: prevPage ? `/?page=${prevPage}` : undefined,
nextHref: nextPage ? `/?page=${nextPage}` : undefined,
};
const viewModel = await buildOrderGridWithPaginationViewModel({
searchParams: await searchParams,
pageSize,
});

return (
<OrderGridWithPaginationClient orders={items} pagination={pagination} />
<OrderGridWithPaginationClient
orders={viewModel.orders}
filters={viewModel.filters}
pagination={viewModel.pagination}
sortState={viewModel.sortState}
/>
);
};

Expand Down
65 changes: 35 additions & 30 deletions components/OrderGrid/OrderGridWithPaginationClient.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,60 @@
'use client';

import { useMemo, useState } from 'react';
import OrderDetailsModal from '@/components/OrderDetailsModal';
import type { Order } from '@/lib/orders/orders.types';
import OrdersGrid from './index';
import type { OrdersGridPaginationData } from './types';
import type {
OrdersGridFilterState,
OrdersGridPaginationData,
OrdersGridSortState,
} from './types';
import { OrdersGridFiltersBar } from './parts/FiltersBar';
import { OrdersGridPagination } from './parts/Pagination';

type SelectionState = {
orderId: string;
dataToken: symbol;
};
import { OrdersGridToolbar } from './parts/Toolbar';
import { useOrderGridWithPaginationController } from './useOrderGridWithPaginationController';

type OrderGridWithPaginationClientProps = {
orders: Order[];
filters: OrdersGridFilterState;
pagination: OrdersGridPaginationData;
sortState: OrdersGridSortState;
};

const OrderGridWithPaginationClient = ({
orders,
filters,
pagination,
sortState,
}: OrderGridWithPaginationClientProps) => {
const dataToken = useMemo(() => Symbol('orders-data-token'), [orders]);
const [selection, setSelection] = useState<SelectionState | null>(null);

const selectedOrder = useMemo(
() => {
if (!selection || selection.dataToken !== dataToken) {
return null;
}

return orders.find((order) => order.id === selection.orderId) ?? null;
},
[orders, selection, dataToken],
);
const {
isFiltersOpen,
selectedOrder,
emptyStateMessage,
toggleFilters,
handleRowClick,
handleModalOpenChange,
} = useOrderGridWithPaginationController({ orders, filters });

return (
<>
<OrdersGridPagination
className="orders-grid__pagination--top"
<OrdersGridToolbar
isFiltersOpen={isFiltersOpen}
onFilterClick={toggleFilters}
pagination={pagination}
/>

{isFiltersOpen ? (
<OrdersGridFiltersBar
filters={filters}
sortState={{ sortBy: sortState.sortBy, sortDir: sortState.sortDir }}
/>
) : null}

<OrdersGrid
emptyStateMessage={emptyStateMessage}
orders={orders}
onRowClick={(order) => {
setSelection({ orderId: order.id, dataToken });
}}
sortState={sortState}
onRowClick={handleRowClick}
/>
<OrdersGridPagination
className="orders-grid__pagination--bottom"
Expand All @@ -54,11 +63,7 @@ const OrderGridWithPaginationClient = ({

<OrderDetailsModal
open={Boolean(selectedOrder)}
onOpenChange={(nextOpen) => {
if (!nextOpen) {
setSelection(null);
}
}}
onOpenChange={handleModalOpenChange}
order={selectedOrder}
/>
</>
Expand Down
Loading
Loading