chore: update app version and enhance UI components

- Bumped NEXT_PUBLIC_APP_VERSION to 2.0.3 for the latest release.
- Improved Cypress test for customer feedback page to handle delayed route transitions.
- Refactored CompanyDetailsPage to enhance layout and added new components for better structure.
- Updated TenderDetails to conditionally render location and currency information based on validity checks.
- Added data-cy attributes to various form elements and tables for improved testing capabilities.
This commit is contained in:
AmirReza Jamali
2026-05-05 15:20:55 +03:30
parent 4b425d6a46
commit f48cb7e249
16 changed files with 713 additions and 113 deletions
@@ -18,6 +18,7 @@ type PropsType<T extends FieldValues> = {
className?: string;
icon?: React.ReactNode;
defaultValue?: string;
dataCy?: string;
handleChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
register?: UseFormRegister<T>;
errors?: FieldErrors<T>;
@@ -33,6 +34,7 @@ export function TextAreaGroup<T extends FieldValues>({
className,
icon,
defaultValue,
dataCy,
handleChange,
register,
errors,
@@ -77,6 +79,7 @@ export function TextAreaGroup<T extends FieldValues>({
required={required}
disabled={disabled}
data-active={active}
data-cy={dataCy}
/>
{icon}
+3
View File
@@ -8,6 +8,7 @@ type PropsType = {
backgroundSize?: "sm" | "default";
name?: string;
checked?: boolean;
dataCy?: string;
onToggle: (e: ToggleEvent<HTMLInputElement>) => void;
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
};
@@ -18,6 +19,7 @@ export function Switch({
backgroundSize,
name,
checked = false,
dataCy,
onToggle,
onChange,
}: PropsType) {
@@ -37,6 +39,7 @@ export function Switch({
id={id}
className="peer sr-only"
checked={checked}
data-cy={dataCy}
/>
<div
className={cn("h-8 w-14 rounded-full bg-gray-3 dark:bg-[#5A616B]", {
@@ -30,6 +30,7 @@ const CompanyCategoryListFilters = ({
return (
<form
className="grid !min-w-full grid-cols-1 gap-4 xl:grid-cols-2"
data-cy="company-categories-filter-form"
onSubmit={handleFilterSubmit(search)}
>
<InputGroup
@@ -38,6 +39,7 @@ const CompanyCategoryListFilters = ({
label="search"
placeholder="Search"
type="search"
dataCy="company-categories-filter-search-input"
/>
<Select
{...filterRegister("published")}
@@ -51,11 +53,13 @@ const CompanyCategoryListFilters = ({
clearable
value={watch("published")}
onClear={() => setValue("published", undefined)}
dataCy="company-categories-filter-published-select"
/>
<div className="flex gap-4">
<button
type="submit"
data-cy="company-categories-filter-submit-button"
className="mt-6 flex w-fit justify-center rounded-lg bg-primary p-[13px] font-medium capitalize text-white hover:bg-opacity-90"
>
{isMutating ? (
@@ -66,6 +70,7 @@ const CompanyCategoryListFilters = ({
</button>
<button
type="button"
data-cy="company-categories-filter-close-button"
className="mt-6 flex w-fit justify-center rounded-lg bg-error p-[13px] font-medium capitalize text-white hover:bg-opacity-90"
onClick={() => setIsFilterModalOpen(false)}
>
@@ -47,12 +47,13 @@ const CompanyCategoriesTable = () => {
} = useCompanyCategoriesPresenter();
return (
<ListWrapper>
<ListWrapper data-cy="company-categories-page">
<ListHeader
onFilter={() => setIsFilterModalOpen(true)}
createButtonText="Create Category"
dataCyPrefix="company-categories"
/>
<Table>
<Table data-cy="company-categories-table">
<TableHeader>
<TableRow className="border-none uppercase [&>th]:text-start">
<TableHead colSpan={100}>Row</TableHead>
@@ -73,6 +74,7 @@ const CompanyCategoriesTable = () => {
{optimisticCategories.map((category, index) => (
<TableRow
key={category.id}
data-cy={`company-categories-table-row-${category.id}`}
className="odd:bg-gray-2 dark:odd:bg-gray-7"
>
<TableCell colSpan={100}>
@@ -84,8 +86,10 @@ const CompanyCategoriesTable = () => {
{unixToDate({ unix: category.created_at, hasTime: true })}
</TableCell>
<TableCell colSpan={100}>
{/* Published: flip UI immediately via useOptimistic; if togglePublished rejects, React rolls the optimistic row back. */}
<Switch
withIcon
dataCy={`company-categories-published-toggle-${category.id}`}
onToggle={() => {}}
onChange={() => {
const nextPublished = !category.published;
@@ -94,7 +98,11 @@ const CompanyCategoriesTable = () => {
id: category.id,
published: nextPublished,
});
await togglePublished(category.id);
try {
await togglePublished(category.id);
} catch {
// useOptimistic automatically reverts when the transition ends
}
});
}}
checked={category.published}
@@ -103,6 +111,8 @@ const CompanyCategoriesTable = () => {
<TableCell className="text-start xl:pr-7.5">
<div className="flex items-center justify-start gap-x-3.5">
<button
type="button"
data-cy={`company-categories-row-delete-${category.id}`}
data-tooltip-id="delete"
data-tooltip-content="Delete"
data-tooltip-place="top"
@@ -117,6 +127,8 @@ const CompanyCategoriesTable = () => {
<TrashIcon />
</button>
<button
type="button"
data-cy={`company-categories-row-edit-${category.id}`}
data-tooltip-id="edit"
data-tooltip-content="Edit"
data-tooltip-place="top"
+6
View File
@@ -87,6 +87,12 @@ const TendersTable = () => {
<TableCell className="text-start" colSpan={100}>
{item.country_code}
</TableCell>
<TableCell className="text-start" colSpan={100}>
{unixToDate({
unix: item.publication_date,
hasTime: true,
})}
</TableCell>
<TableCell className="text-start" colSpan={100}>
{unixToDate({
unix: item.submission_deadline,
@@ -57,6 +57,7 @@ const useTenderListPresenter = () => {
"row",
"title",
"country code",
"publication date",
"submission deadline",
"tender deadline",
"created at",
@@ -17,15 +17,20 @@ const CreateCompanyCategoryForm = ({ defaultValues, editMode, id }: IProps) => {
const { errors, handleSubmit, onSubmit, register } =
useCreateCompanyCategoryPresenter({ defaultValues, editMode, id });
return (
<form className="grid grid-cols-1 gap-9" onSubmit={handleSubmit(onSubmit)}>
<form
className="grid grid-cols-1 gap-9"
data-cy="company-category-form"
onSubmit={handleSubmit(onSubmit)}
>
<ShowcaseSection
title="Create Company Category"
title={editMode ? "Edit Company Category" : "Create Company Category"}
className="grid grid-cols-1 gap-5 md:grid-cols-2"
>
<div className="flex flex-col gap-2 md:col-span-1">
<InputGroup
label="Name"
required
dataCy="company-category-form-name-input"
{...register("name", {
required: {
value: true,
@@ -51,6 +56,7 @@ const CreateCompanyCategoryForm = ({ defaultValues, editMode, id }: IProps) => {
<div className="flex flex-col gap-2 md:col-span-1">
<TextAreaGroup
label="Description"
dataCy="company-category-form-description-input"
{...register("description", {
minLength: {
value: 10,