Эх сурвалжийг харах

RHL-028 refactor(search): enhance SearchForm layout and improve SearchDateRangePicker usability

Code_Uwe 2 долоо хоног өмнө
parent
commit
9f928b4ed7

+ 71 - 82
components/search/SearchForm.jsx

@@ -1,6 +1,7 @@
 "use client";
 "use client";
 
 
 import React from "react";
 import React from "react";
+import { AlertCircleIcon } from "lucide-react";
 
 
 import { SEARCH_SCOPE } from "@/lib/frontend/search/urlState";
 import { SEARCH_SCOPE } from "@/lib/frontend/search/urlState";
 
 
@@ -13,7 +14,6 @@ import SearchDateRangePicker from "@/components/search/form/SearchDateRangePicke
 import SearchDateFilterChip from "@/components/search/form/SearchDateFilterChip";
 import SearchDateFilterChip from "@/components/search/form/SearchDateFilterChip";
 
 
 import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
 import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
-import { AlertCircleIcon } from "lucide-react";
 
 
 export default function SearchForm({
 export default function SearchForm({
 	branch,
 	branch,
@@ -40,11 +40,7 @@ export default function SearchForm({
 }) {
 }) {
 	const canSearch = typeof qDraft === "string" && qDraft.trim().length > 0;
 	const canSearch = typeof qDraft === "string" && qDraft.trim().length > 0;
 
 
-	// RHL-038 UI behavior:
-	// - Single scope shows an extra combobox (branch picker).
-	// - Multi/All does not.
-	// - We animate the combobox container (max-width/max-height/opacity) so the
-	//   query block (input + search button) grows/shrinks smoothly.
+	// SINGLE scope (admin/dev only) shows an extra branch combobox.
 	const showSingleBranchCombobox = Boolean(
 	const showSingleBranchCombobox = Boolean(
 		isAdminDev && scope === SEARCH_SCOPE.SINGLE
 		isAdminDev && scope === SEARCH_SCOPE.SINGLE
 	);
 	);
@@ -61,72 +57,82 @@ export default function SearchForm({
 				}}
 				}}
 				className="space-y-4"
 				className="space-y-4"
 			>
 			>
-				{/* 
-					Layout goal:
-					- Desktop: everything on one line (scope + optional single combobox | query | date range | limit)
-					- Mobile: stack to avoid horizontal overflow
-				*/}
-				<div className="flex flex-col gap-3 lg:flex-row items-start lg:flex-nowrap">
-					{/* Left block: scope + (animated) single-branch combobox */}
-					{isAdminDev ? (
-						<div className="flex items-end shrink-0">
-							<SearchScopeSelect
-								branch={branch}
-								scope={scope}
-								onScopeChange={onScopeChange}
-								isSubmitting={isSubmitting}
-							/>
+				{/* Row 1: query full-width */}
+				<div className="w-full">
+					<SearchQueryBox
+						qDraft={qDraft}
+						onQDraftChange={onQDraftChange}
+						onSubmit={onSubmit}
+						currentQuery={currentQuery}
+						isSubmitting={isSubmitting}
+						canSearch={canSearch}
+					/>
+				</div>
 
 
-							{/* 
-								Animated presence (no mount/unmount):
-								- When hidden: max-w-0/max-h-0 + opacity-0 so it takes no space.
-								- When shown: expands to a reasonable max size.
-								This animation drives the smooth resize of the query input block.
-							*/}
-							<div
-								className={[
-									"overflow-hidden transition-all duration-200 ease-in-out",
-									showSingleBranchCombobox
-										? "ml-2 max-w-44 max-h-24 opacity-100"
-										: "ml-0 max-w-0 max-h-0 opacity-0 pointer-events-none",
-								].join(" ")}
-								aria-hidden={showSingleBranchCombobox ? "false" : "true"}
-							>
-								<SearchSingleBranchCombobox
+				{/* Row 2: left controls + spacer + limit on the right */}
+				<div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
+					{/* Left group: scope (+ optional single branch combobox) + date range */}
+					<div className="flex flex-col gap-3 sm:flex-row sm:items-end">
+						{isAdminDev ? (
+							<div className="flex items-end gap-3">
+								<SearchScopeSelect
 									branch={branch}
 									branch={branch}
-									branchesStatus={branchesStatus}
-									availableBranches={availableBranches}
-									onSingleBranchChange={onSingleBranchChange}
-									// Disable when hidden so it can't be focused/clicked.
-									isSubmitting={isSubmitting || !showSingleBranchCombobox}
+									scope={scope}
+									onScopeChange={onScopeChange}
+									isSubmitting={isSubmitting}
 								/>
 								/>
+
+								{/* Animated presence (kept for smoothness when SINGLE shows the extra combobox) */}
+								<div
+									className={[
+										"overflow-hidden transition-all duration-200 ease-in-out",
+										showSingleBranchCombobox
+											? "max-w-44 max-h-24 opacity-100"
+											: "max-w-0 max-h-0 opacity-0 pointer-events-none",
+									].join(" ")}
+									aria-hidden={showSingleBranchCombobox ? "false" : "true"}
+								>
+									<SearchSingleBranchCombobox
+										branch={branch}
+										branchesStatus={branchesStatus}
+										availableBranches={availableBranches}
+										onSingleBranchChange={onSingleBranchChange}
+										isSubmitting={isSubmitting || !showSingleBranchCombobox}
+									/>
+								</div>
 							</div>
 							</div>
-						</div>
-					) : null}
-
-					{/* Middle block: query must take the most space */}
-					<div className="flex-1 min-w-0">
-						<SearchQueryBox
-							qDraft={qDraft}
-							onQDraftChange={onQDraftChange}
-							onSubmit={onSubmit}
-							currentQuery={currentQuery}
-							isSubmitting={isSubmitting}
-							canSearch={canSearch}
-						/>
-					</div>
+						) : null}
 
 
-					{/* Date range picker */}
-					<div className="shrink-0">
-						<SearchDateRangePicker
-							from={from}
-							to={to}
-							onDateRangeChange={onDateRangeChange}
-							isSubmitting={isSubmitting}
-						/>
+						<div className="shrink-0 flex items-end gap-4">
+							<SearchDateRangePicker
+								from={from}
+								to={to}
+								onDateRangeChange={onDateRangeChange}
+								isSubmitting={isSubmitting}
+							/>
+
+							{/* Active date filter chip (quick clear) */}
+							{hasDateFilter ? (
+								<div className="flex flex-wrap items-center gap-2 mb-2">
+									<span className="text-xs text-muted-foreground">
+										Aktive Filter:
+									</span>
+
+									<SearchDateFilterChip
+										from={from}
+										to={to}
+										isSubmitting={isSubmitting}
+										onClear={() => {
+											if (typeof onDateRangeChange !== "function") return;
+											onDateRangeChange({ from: null, to: null });
+										}}
+									/>
+								</div>
+							) : null}
+						</div>
 					</div>
 					</div>
 
 
-					{/* Right block: limit stays “content-sized” */}
+					{/* Right group: limit aligned right */}
 					<div className="shrink-0">
 					<div className="shrink-0">
 						<SearchLimitSelect
 						<SearchLimitSelect
 							limit={limit}
 							limit={limit}
@@ -146,23 +152,6 @@ export default function SearchForm({
 				</Alert>
 				</Alert>
 			) : null}
 			) : null}
 
 
-			{/* Active date filter chip (quick clear) */}
-			{hasDateFilter ? (
-				<div className="flex flex-wrap items-center gap-2">
-					<span className="text-xs text-muted-foreground">Aktive Filter:</span>
-
-					<SearchDateFilterChip
-						from={from}
-						to={to}
-						isSubmitting={isSubmitting}
-						onClear={() => {
-							if (typeof onDateRangeChange !== "function") return;
-							onDateRangeChange({ from: null, to: null });
-						}}
-					/>
-				</div>
-			) : null}
-
 			{/* Multi scope branch picker remains below */}
 			{/* Multi scope branch picker remains below */}
 			{isAdminDev && scope === SEARCH_SCOPE.MULTI ? (
 			{isAdminDev && scope === SEARCH_SCOPE.MULTI ? (
 				<SearchMultiBranchPicker
 				<SearchMultiBranchPicker

+ 6 - 15
components/search/form/SearchDateRangePicker.jsx

@@ -374,15 +374,7 @@ export default function SearchDateRangePicker({
 
 
 							<div className="flex flex-wrap gap-2">
 							<div className="flex flex-wrap gap-2">
 								{presetsRow2.map((p) => (
 								{presetsRow2.map((p) => (
-									<Badge
-										key={p.key}
-										asChild
-										className={[
-											"bg-white text-black border-border",
-											"hover:bg-white/90",
-											"dark:bg-white dark:text-black",
-										].join(" ")}
-									>
+									<Badge key={p.key} asChild>
 										<button
 										<button
 											type="button"
 											type="button"
 											className="cursor-pointer select-none disabled:opacity-60"
 											className="cursor-pointer select-none disabled:opacity-60"
@@ -397,12 +389,7 @@ export default function SearchDateRangePicker({
 							</div>
 							</div>
 						</div>
 						</div>
 
 
-						<div className="flex items-center justify-between gap-4 pt-1">
-							<p className="text-xs text-muted-foreground">
-								Tipp: Für einen einzelnen Tag setzen Sie <b>Von</b> und{" "}
-								<b>Bis</b> auf dasselbe Datum.
-							</p>
-
+						<div className="flex justify-end pt-1">
 							<Button
 							<Button
 								type="button"
 								type="button"
 								variant="outline"
 								variant="outline"
@@ -412,6 +399,10 @@ export default function SearchDateRangePicker({
 								Zurücksetzen
 								Zurücksetzen
 							</Button>
 							</Button>
 						</div>
 						</div>
+						<p className="text-xs text-muted-foreground text-center">
+							Tipp: Für einen einzelnen Tag setzen Sie <b>Von</b> und <b>Bis</b>{" "}
+							auf dasselbe Datum.
+						</p>
 					</div>
 					</div>
 				</PopoverContent>
 				</PopoverContent>
 			</Popover>
 			</Popover>