prod-wag-backend-automate-s.../WebServices/client-frontend/src/components/layouts
Berkay 71c808a5c3 updated components common header layouts 2025-05-03 13:51:02 +03:00
..
DashboardLayout.tsx updated components common header layouts 2025-05-03 13:51:02 +03:00
PageTemplate.tsx updated components common header layouts 2025-05-03 13:51:02 +03:00
README.md updated lang change and FormDisplay Components 2025-04-30 14:30:22 +03:00
schema.ts updated components common header layouts 2025-05-03 13:51:02 +03:00

README.md

Modular Dashboard Layout System

This directory contains reusable layout components for building dashboard pages with a consistent structure and appearance.

Components

DashboardLayout

The DashboardLayout component provides the overall page structure with:

  • Sidebar navigation
  • Header
  • Main content area

PageTemplate

The PageTemplate component provides a standardized structure for page content with:

  • Header section with title and selection components
  • Search filters section
  • Action buttons section
  • Pagination tools section
  • Content display section
  • Form display for create/update/view modes

Usage Example

Here's an example of how to use these components to create a new dashboard page:

"use client";
import React, { useState } from "react";
import { useApiData } from "@/components/common/hooks/useApiData";
import { CardDisplay } from "@/components/common/CardDisplay";
import { FormDisplay } from "@/components/common/FormDisplay/FormDisplay";
import { TextQueryModifier, SelectQueryModifier, TypeQueryModifier } from "@/components/common/QueryModifiers";
import { Card, CardContent } from "@/components/ui/card";
import { Language } from "@/components/common/HeaderSelections/LanguageSelectionComponent";
import { FormMode } from "@/components/common/FormDisplay/types";
import { PageTemplate } from "@/components/layouts/PageTemplate";
import type { GridSize } from "@/components/common/HeaderSelections/GridSelectionComponent";

// Import your schema and translations
import * as schema from "./schema";
import { translations } from "./language";

const ExamplePage: React.FC<{ lang: "en" | "tr", queryParams: any }> = ({ 
  lang = "en", 
  queryParams 
}) => {
  // API data hook
  const {
    data,
    pagination,
    loading,
    error,
    updatePagination,
    refetch
  } = useApiData<schema.ExampleData>('/api/examples');

  // State management
  const [mode, setMode] = useState<FormMode>("list");
  const [selectedItem, setSelectedItem] = useState<schema.ExampleData | null>(null);
  const [gridCols, setGridCols] = useState<GridSize>(3);
  const [currentLang, setCurrentLang] = useState<Language>(lang as Language);

  // Fields to display in cards
  const showFields = ["name", "type", "status"];

  // Query handling
  const handleQueryChange = (key: string, value: string | null) => {
    const newQuery = { ...pagination.query };

    if (value === null || value.trim() === "") {
      delete newQuery[key];
    } else {
      newQuery[key] = value;
    }

    updatePagination({
      page: 1,
      query: newQuery,
    });
  };

  // Reset all filters
  const handleResetAllFilters = () => {
    updatePagination({
      page: 1,
      query: {},
    });
  };

  // Action handlers
  const handleCardClick = (item: schema.ExampleData) => {
    console.log("Card clicked:", item);
  };

  const handleViewClick = (item: schema.ExampleData) => {
    setSelectedItem(item);
    setMode("view");
  };

  const handleUpdateClick = (item: schema.ExampleData) => {
    setSelectedItem(item);
    setMode("update");
  };

  const handleCreateClick = () => {
    setSelectedItem(null);
    setMode("create");
  };

  const handleCancel = () => {
    setMode("list");
    setSelectedItem(null);
  };

  // Search section component
  const SearchSection = (
    <div className="flex flex-col space-y-4">
      <div className="flex space-x-4">
        {/* Type selector */}
        <TypeQueryModifier
          fieldKey="type"
          value={pagination.query["type"] || ""}
          options={[
            { value: "type1", label: translations[lang].type1 },
            { value: "type2", label: translations[lang].type2 }
          ]}
          onQueryChange={handleQueryChange}
          translations={translations}
          lang={lang}
        />
      </div>
      
      <div className="flex space-x-4">
        {/* Text search */}
        <TextQueryModifier
          fieldKey="name"
          value={pagination.query["name__ilike"] ? pagination.query["name__ilike"].replace(/%/g, "") : ""}
          label={translations[lang].search || "Search"}
          onQueryChange={handleQueryChange}
          translations={translations}
          lang={lang}
        />
        
        {/* Status dropdown */}
        <SelectQueryModifier
          fieldKey="status"
          value={pagination.query["status"] || ""}
          label={translations[lang].status || "Status"}
          options={[
            { value: "active", label: translations[lang].active || "Active" },
            { value: "inactive", label: translations[lang].inactive || "Inactive" }
          ]}
          onQueryChange={handleQueryChange}
          translations={translations}
          lang={lang}
        />
      </div>
      
      {/* Reset filters button */}
      <div className="flex justify-end">
        <button 
          onClick={handleResetAllFilters}
          className="px-4 py-2 bg-gray-100 rounded-md hover:bg-gray-200"
        >
          {translations[lang].resetAll || "Reset All"}
        </button>
      </div>
    </div>
  );

  // Form component
  const FormComponent = selectedItem || mode === "create" ? (
    <FormDisplay<schema.ExampleData>
      initialData={selectedItem || undefined}
      mode={mode}
      refetch={refetch}
      setMode={setMode}
      setSelectedItem={setSelectedItem}
      onCancel={handleCancel}
      lang={lang}
      translations={translations}
      formProps={{
        fieldDefinitions: mode === 'create' ? schema.createFieldDefinitions :
          mode === 'update' ? schema.updateFieldDefinitions :
            schema.viewFieldDefinitions,
        validationSchema: mode === 'create' ? schema.CreateExampleSchema :
          mode === 'update' ? schema.UpdateExampleSchema :
            schema.ViewExampleSchema,
        fieldsByMode: schema.fieldsByMode
      }}
    />
  ) : null;

  // Content display component
  const ContentDisplay = (
    <CardDisplay
      showFields={showFields}
      data={data}
      lang={lang}
      translations={translations}
      error={error}
      loading={loading}
      titleField="name"
      onCardClick={handleCardClick}
      gridCols={gridCols}
      showViewIcon={true}
      showUpdateIcon={true}
      onViewClick={handleViewClick}
      onUpdateClick={handleUpdateClick}
    />
  );

  return (
    <PageTemplate
      title={translations[lang].examplePageTitle || "Example Page"}
      lang={lang}
      translations={translations}
      searchSection={SearchSection}
      data={data}
      pagination={pagination}
      updatePagination={updatePagination}
      loading={loading}
      error={error}
      refetch={refetch}
      contentDisplay={ContentDisplay}
      formComponent={FormComponent}
      mode={mode}
      setMode={setMode}
      handleCreateClick={handleCreateClick}
      handleCancel={handleCancel}
      setLang={setCurrentLang}
    />
  );
};

export default ExamplePage;

Integration with Next.js App Router

To use these components with Next.js App Router, update your page component like this:

// src/app/(DashboardLayout)/your-page/page.tsx
import React from "react";
import { retrievePageByUrl } from "@/eventRouters/pageRetriever";
import DashboardLayout from "@/components/layouts/DashboardLayout";

async function YourPage({
  searchParams,
}: {
  searchParams: Promise<{ [key: string]: string | undefined }>;
}) {
  const activePage = "/your-page";
  const searchParamsInstance = await searchParams;
  const lang = (searchParamsInstance?.lang as "en" | "tr") || "en";
  const PageComponent = retrievePageByUrl(activePage);

  return (
    <DashboardLayout lang={lang} activePage={activePage}>
      <PageComponent lang={lang} queryParams={searchParamsInstance} />
    </DashboardLayout>
  );
}

export default YourPage;

This modular approach makes it easy to create new dashboard pages with consistent structure and behavior.