# Generated file: frontend_assets.py

DIR__APP__FILE__PAGE__TSX = '''// src/app/page.tsx
import React from 'react';
import {{ redirect }} from 'next/navigation';
import modalConfig from '../components/modalConfig';

const HomePage: React.FC = () => {{
  const modals = Object.keys(modalConfig);

  // Perform server-side redirection
  redirect(`/${{modals[1]}}`);

  return null; // No need to return any JSX as the redirection happens immediately
}};

export default HomePage;'''

DIR__APP__FILE__LAYOUT__TSX = '''import type {{ Metadata }} from "next";
import {{ Inter }} from "next/font/google";
import "./globals.css";

const inter = Inter({{ subsets: ["latin"] }});

export const metadata: Metadata = {{
  title: "Create Next App",
  description: "Generated by create next app",
}};

export default function RootLayout({{
  children,
}}: Readonly<{{
  children: React.ReactNode;
}}>) {{
  return (
    <html lang="en">
      <body className={{inter.className}}>{{children}}</body>
    </html>
  );
}}'''

DIR__APP__FILE__GLOBALS__CSS = '''@tailwind base;
@tailwind components;
@tailwind utilities;
@import '../styles/scrollbar.css';'''

DIR__COMPONENTS__FILE__EDIT_MODAL__TSX = '''import React, {{ useState, useCallback, useEffect }} from 'react';
import {{ useRouter }} from 'next/router';
import modalConfig from './modalConfig';
import {{ validateField, open_ai_quality_checks }} from './validationUtils';

interface EditModalProps {{
  modalName: string;
  apiHost: string;
  columns: string[];
  rowData: any[];
  onClose: (updatedData: any[] | null) => void;
}}

const EditModal: React.FC<EditModalProps> = ({{ modalName, apiHost, columns, rowData, onClose }}) => {{
  const router = useRouter(); // Use router
  const [formData, setFormData] = useState<{{ [key: string]: any }}>({{}});
  const [errors, setErrors] = useState<{{ [key: string]: string | null }}>({{}});
  const [dynamicOptions, setDynamicOptions] = useState<{{ [key: string]: string[] }}>({{}});
  const config = modalConfig[modalName];

  useEffect(() => {{
    const initialData = columns.reduce((acc, col, index) => {{
      acc[col] = rowData[0][index]; // Assuming rowData is an array of arrays and we are interested in the first row
      return acc;
    }}, {{}} as {{ [key: string]: any }});
    setFormData(initialData);
  }}, [rowData, columns]);

  const evalCondition = useCallback((condition: string) => {{
    const conditionToEvaluate = condition.replace(/(\\w+)/g, (match) => {{
      if (formData.hasOwnProperty(match)) {{
        return `formData['${{match}}']`;
      }}
      return `'${{match}}'`;
    }});
    try {{
      const result = new Function('formData', `return ${{conditionToEvaluate}};`)(formData);
      return result;
    }} catch (e) {{
      console.error('Error evaluating condition:', condition, e);
      return false;
    }}
  }}, [formData]); // Include formData in dependencies

  const updateDynamicOptions = useCallback(() => {{
    const newDynamicOptions: {{ [key: string]: string[] }} = {{}};
    if (config.conditional_options) {{
      for (const [field, conditions] of Object.entries(config.conditional_options)) {{
        for (const conditionObj of conditions) {{
          if (evalCondition(conditionObj.condition)) {{
            newDynamicOptions[field] = conditionObj.options;
            break; // Stop checking other conditions if one matches
          }}
        }}
      }}
    }}
    setDynamicOptions(newDynamicOptions);
  }}, [config, evalCondition]); // Include config and evalCondition in dependencies

  useEffect(() => {{
    updateDynamicOptions();
  }}, [updateDynamicOptions]);

  const getCookie = (name: string): string | undefined => {{
    const cookies = document.cookie.split(';').reduce((acc, cookie) => {{
      const [key, value] = cookie.trim().split('=');
      acc[key] = value;
      return acc;
    }}, {{}} as {{ [key: string]: string }});
    return cookies[name];
  }};

  const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {{
    const {{ name, value, type }} = e.target;

    setFormData((prevData) => {{
      if (type === 'checkbox') {{
        if (e.target instanceof HTMLInputElement) {{
          const checked = e.target.checked;
          const currentValues = prevData[name] ? prevData[name].split(';') : [];
          const updatedValues = checked
            ? [...currentValues, value]
            : currentValues.filter((item: string) => item !== value);
          return {{ ...prevData, [name]: updatedValues.join(';') }};
        }}
      }} else {{
        return {{ ...prevData, [name]: value }};
      }}
    }});

    if (config.validation_rules && config.validation_rules[name]) {{
      const error = validateField(name, value, config.validation_rules[name]);
      setErrors((prevErrors) => ({{ ...prevErrors, [name]: error }}));
    }}
  }};

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {{
    e.preventDefault();
    let valid = true;
    const newErrors: {{ [key: string]: string | null }} = {{}};

    if (config.validation_rules) {{
      for (const field of Object.keys(config.validation_rules)) {{
        const error = validateField(field, formData[field], config.validation_rules[field]);
        if (error) {{
          valid = false;
          newErrors[field] = error;
        }}
      }}
    }}

    if (config.ai_quality_checks) {{
      for (const field of Object.keys(config.ai_quality_checks)) {{
        const aiErrors = await open_ai_quality_checks(field, formData[field], config.ai_quality_checks[field]);
        if (aiErrors.length > 0) {{
          valid = false;
          newErrors[field] = aiErrors.join(', ');
        }}
      }}
    }}

    setErrors(newErrors);

    if (!valid) {{
      alert('Please fix the validation errors.');
      return;
    }}

    const updateData = columns.reduce((acc, col) => {{
      acc[col] = formData[col];
      return acc;
    }}, {{}} as {{ [key: string]: any }});

    const user_id = getCookie('user_id');

    if (user_id) {{
      updateData['user_id'] = user_id;
    }} else {{
      console.error('User ID not found in cookies');
      onClose(null);
      return;
    }}

    try {{
      const response = await fetch(`${{apiHost}}update/${{modalName}}/${{rowData[0][0]}}`, {{
        method: 'PUT',
        headers: {{
          'Content-Type': 'application/json',
        }},
        body: JSON.stringify(updateData),
      }});

      const result = await response.json();
      if (result.status === 'success') {{
        alert('Record updated successfully');
        router.reload(); // Refresh the page after a successful edit
        onClose([formData]); // Pass updated data back to parent
      }} else {{
        console.error('Failed to update data:', result);
        onClose(null);
      }}
    }} catch (error) {{
      console.error('Error updating data:', error);
      onClose(null);
    }}
  }};

  const isUrl = (value: string): boolean => {{
    try {{
      new URL(value);
      return true;
    }} catch (_) {{
      return false;
    }}
  }};

  const renderField = (col: string) => {{
    const orTypeOptions = Object.entries(config.options).find(([key]) => key.startsWith(`${{col}}[OR]`));
    const xorTypeOptions = Object.entries(config.options).find(([key]) => key.startsWith(`${{col}}[XOR]`));

    if (orTypeOptions) {{
      return (
        <div className="flex flex-col space-y-2">
          {{orTypeOptions[1]?.map((option: string) => (
            <label key={{option}} className="flex items-center cursor-pointer">
              <input
                type="checkbox"
                name={{col}}
                value={{option}}
                checked={{formData[col]?.split(';').includes(option) || false}}
                onChange={{handleChange}}
                className="h-5 w-5 cursor-pointer appearance-none rounded-md border border-yellow-100/30 transition-all checked:bg-yellow-100/50 checked:border-none"
              />
              <span className="ml-3 text-yellow-100/50">{{option}}</span>
            </label>
          ))}}
        </div>
      );
    }} else if (xorTypeOptions) {{
      return (
        <select
          name={{col}}
          value={{formData[col] || ''}}
          onChange={{handleChange}}
          className="bg-black text-yellow-100/50 px-3 py-2 rounded-lg border border-yellow-100/30 w-full text-sm"
        >
          <option value="" disabled>
            Select {{col}}
          </option>
          {{xorTypeOptions[1]?.map((option: string) => (
            <option key={{option}} value={{option}}>
              {{option}}
            </option>
          ))}}
        </select>
      );
    }} else if (dynamicOptions[col]) {{
      return (
        <select
          name={{col}}
          value={{formData[col] || ''}}
          onChange={{handleChange}}
          className="bg-black text-yellow-100/50 px-3 py-2 rounded-lg border border-yellow-100/30 w-full text-sm"
        >
          <option value="" disabled>
            Select {{col}}
          </option>
          {{dynamicOptions[col]?.map((option: string) => (
            <option key={{option}} value={{option}}>
              {{option}}
            </option>
          ))}}
        </select>
      );
    }} else {{
      return (
        <input
          type="text"
          name={{col}}
          value={{formData[col] || ''}}
          onChange={{handleChange}}
          className="bg-black text-yellow-100/50 px-3 py-2 rounded-lg border border-yellow-100/30 w-full text-sm"
        />
      );
    }}
  }};

  return (
    <div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 py-4">
      <div className="bg-black border border-yellow-100/30 p-6 rounded-lg w-3/4 max-h-screen overflow-y-auto">
        <h2 className="text-yellow-100/50 text-center mb-8 text-2xl">Edit {{modalName}}</h2>
        <form onSubmit={{handleSubmit}}>
          <div className="grid grid-cols-2 gap-4">
            {{/* Fields within the update scope */}}
            {{columns.filter(col => config.scopes.update.includes(col)).map(col => (
              <div key={{col}} className="mb-2">
                <label className="block text-yellow-100/50 ms-1 text-sm">{{col}}</label>
                {{renderField(col)}}
                {{errors[col] && <p className="text-red-500">{{errors[col]}}</p>}}
              </div>
            ))}}
          </div>
          <div className="flex justify-end mt-4">
            <button
              type="button"
              onClick={{() => onClose(null)}}
              className="bg-black hover:bg-yellow-100/70 text-yellow-100/50 hover:text-black py-1 px-4 rounded-lg text-sm border border-yellow-100/30 hover:border-black mr-2"
            >
              Cancel
            </button>
            <button
              type="submit"
              className="bg-black hover:bg-yellow-100/70 text-yellow-100/50 hover:text-black py-1 px-4 rounded-lg text-sm border border-yellow-100/30 hover:border-black"
            >
              Save
            </button>
          </div>
          <div className="grid grid-cols-2 gap-4 mt-4">
            {{/* Remaining fields */}}
            {{columns.filter(col => !config.scopes.update.includes(col)).map(col => (
              <div key={{col}} className="mb-2">
                <label className="block text-yellow-100/50 ms-1 text-sm">{{col}}</label>
                <div className="bg-black text-yellow-100/30 border border-yellow-100/10 px-3 py-2 rounded-lg w-full">
                  {{isUrl(formData[col]) ? (
                    <button
                      type="button"
                      onClick={{() => window.open(formData[col], '_blank')}}
                      className="bg-black border border-yellow-100/30 text-yellow-100/50 hover:bg-yellow-100/70 hover:text-black hover:border-black px-2 rounded-lg"
                    >
                      Open URL
                    </button>
                  ) : (
                    formData[col]
                  )}}
                </div>
                {{errors[col] && <p className="text-red-500">{{errors[col]}}</p>}}
              </div>
            ))}}
          </div>
        </form>
      </div>
    </div>
  );
}};

export default EditModal;'''

DIR__COMPONENTS__FILE__CRUD_UTILS__TSX = '''// src/components/crudUtils.tsx
import modalConfig from './modalConfig';

export const handleCreate = (setCreateModalOpen: (open: boolean) => void) => {{
  setCreateModalOpen(true);
}};

export const closeCreateModal = (setCreateModalOpen: (open: boolean) => void) => {{
  setCreateModalOpen(false);
}};

export const getUserIDFromCookies = (): string | undefined => {{
  if (typeof document !== 'undefined') {{
    const cookies = document.cookie.split(';').reduce((acc: {{ [key: string]: string }}, cookie) => {{
      const [key, value] = cookie.trim().split('=');
      acc[key] = value;
      return acc;
    }}, {{}} as {{ [key: string]: string }});

    return cookies.user_id;
  }}
  return undefined;
}};


export const fetchData = async (
  apiHost: string,
  modal: string,
  routeKey: string,
  setData: React.Dispatch<React.SetStateAction<any[]>>,
  setColumns: React.Dispatch<React.SetStateAction<any[]>>
) => {{

  const config = modalConfig[modal];
  const userId = getUserIDFromCookies();

  try {{
    const readRoute = config.read_routes[routeKey];
    const apiUrl = readRoute.belongs_to_user_id && userId
      ? `${{apiHost}}read/${{modal}}/${{routeKey}}/${{userId}}`
      : `${{apiHost}}read/${{modal}}/${{routeKey}}`;

    const response = await fetch(apiUrl);
    const result = await response.json();
    setColumns(result.columns || []);
    setData(result.data || []);
  }} catch (error) {{
    setColumns([]);
    setData([]);
  }}
}};


export const handleDelete = async (apiHost: string, modal: string, id: number, userId: number) => {{
  try {{
    const response = await fetch(`${{apiHost}}delete/${{modal}}/${{id}}`, {{
      method: 'DELETE',
      headers: {{
        'Content-Type': 'application/json',
      }},
      body: JSON.stringify({{ user_id: userId }}),
    }});
    const result = await response.json();
    /*
    if (result.status === 'success') {{
      setData(data.filter((row: any) => row[0] !== id));
    }}
    */
  }} catch (error) {{
    console.error('Error deleting data:', error);
  }}
}};



export const handleEdit = (
  row: {{ [key: string]: any }},
  setEditRowData: React.Dispatch<React.SetStateAction<any[]>>, // Expect an array
  setEditModalOpen: React.Dispatch<React.SetStateAction<boolean>>
) => {{
  setEditRowData([row]); // Wrap the row in an array
  setEditModalOpen(true);
}};

export const closeEditModal = (
  updatedData: any[] | null,
  columns: string[],
  setData: React.Dispatch<React.SetStateAction<any[]>>,
  setEditModalOpen: React.Dispatch<React.SetStateAction<boolean>>
) => {{
  if (updatedData && updatedData.length > 0) {{
    //console.log('56', updatedData);
    const updatedRow = updatedData[0]; // Assuming updatedData contains an array with a single object

    const updatedId = updatedRow.id; // Assuming the row object has an 'id' property
    //console.log('60', updatedId);

    setData(prevData => {{
      const newData = prevData.map(row => {{
        // Assuming `row` is an array and the first element is the id
        if (row[0] === updatedId) {{
          return columns.map(column => updatedRow[column] !== undefined ? updatedRow[column] : row[columns.indexOf(column)]);
        }}
        return row;
      }});
      //console.log('72', newData);
      return newData;
    }});
  }}
  setEditModalOpen(false);
}};'''

DIR__COMPONENTS__FILE__FORMAT_UTILS__TSX = '''export const formatDateTime = (dateTime: string): string => {{
  // Check if the input is a simple number
  if (!isNaN(Number(dateTime))) {{
    return dateTime;
  }}

  const date = new Date(dateTime);
  if (isNaN(date.getTime())) {{
    // Return the original value if the input is not a valid date string
    return dateTime;
  }}

  const year = date.getFullYear();
  const month = ('0' + (date.getMonth() + 1)).slice(-2);
  const day = ('0' + date.getDate()).slice(-2);
  const hours = ('0' + date.getHours()).slice(-2);
  const minutes = ('0' + date.getMinutes()).slice(-2);
  const seconds = ('0' + date.getSeconds()).slice(-2);

  return `${{year}}-${{month}}-${{day}} ${{hours}}:${{minutes}}:${{seconds}}`;
}};



  export const isValidUrl = (url: string) => {{
    try {{
      new URL(url);
      return true;
    }} catch (_) {{
      return false;
    }}
  }};'''

DIR__COMPONENTS__FILE__SEARCH_UTILS__TSX = '''export const handleSearchSubmit = async (
  apiHost: string,
  modal: string,
  queryInput: string,
  setData: React.Dispatch<React.SetStateAction<any[]>>,
  setQueryError: React.Dispatch<React.SetStateAction<string | null>>
) => {{
  try {{
    const response = await fetch(`${{apiHost}}search/${{modal}}`, {{
      method: 'POST',
      headers: {{
        'Content-Type': 'application/json',
      }},
      body: JSON.stringify({{ search_string: queryInput.trim() }}),
    }});
    const result = await response.json();
    if (response.ok) {{
      setData(result.data);
      setQueryError(null);
    }} else {{
      console.error('Error fetching search results:', result);
      setQueryError(result.error || 'Unknown error occurred');
    }}
  }} catch (error) {{
    console.error('Error fetching search results:', error);
    if (error instanceof Error) {{
      setQueryError(error.message || 'Unknown error occurred');
    }} else {{
      setQueryError('Unknown error occurred');
    }}
  }}
}};'''

DIR__COMPONENTS__FILE__DYNAMIC_TABLE__TSX = '''import React, {{ useState, useEffect, useMemo, useCallback }} from 'react';
import CreateModal from './CreateModal';
import EditModal from './EditModal';
import SearchInput from './SearchInput';
import modalConfig from './modalConfig';
import {{ handleCreate, closeCreateModal, fetchData, handleDelete, handleEdit, closeEditModal }} from './crudUtils';
import {{ isValidUrl, formatDateTime }} from './formatUtils';
import {{ downloadCSV }} from './downloadUtils';

interface DynamicTableProps {{
  modal: string;
}}

const DynamicTable: React.FC<DynamicTableProps> = ({{ modal }}) => {{

  const apiHost = process.env.NEXT_PUBLIC_API_HOST;
  const [data, setData] = useState<any[]>([]);
  const [columns, setColumns] = useState<any[]>([]);
  const [filteredData, setFilteredData] = useState<any[]>([]);
  const [isCreateModalOpen, setCreateModalOpen] = useState(false);
  const [isEditModalOpen, setEditModalOpen] = useState(false);
  const [editRowData, setEditRowData] = useState<any[]>([]);
  const [searchInput, setSearchInput] = useState('');
  const [searchError, setSearchError] = useState<string | null>(null);
  const [activeTab, setActiveTab] = useState<string | null>(null);

  const readRoutes = useMemo(() => {{
    return Object.keys(modalConfig[modal as string]?.read_routes || {{}});
  }}, [modal]);

  useEffect(() => {{
    if (readRoutes.length > 0) {{
      setActiveTab(readRoutes[0]);
    }}
  }}, [readRoutes]);

  useEffect(() => {{
    if (activeTab) {{
      fetchData(apiHost as string, modal, activeTab, data => {{
        setData(data);
        setFilteredData(data);
      }}, setColumns);
    }}
  }}, [apiHost, modal, activeTab]);

  const handleSearchInputChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {{
    setSearchInput(event.target.value);
    const lowerCaseSearchInput = event.target.value.toLowerCase();

    if (!lowerCaseSearchInput) {{
      setFilteredData(data);
    }} else {{
      const filtered = data.filter(row =>
        row.some((cell: unknown) =>
          cell !== null && cell !== undefined && cell.toString().toLowerCase().includes(lowerCaseSearchInput)
        )
      );
      setFilteredData(filtered);
    }}
  }}, [data]);

  const columnIndices = modalConfig[modal]?.scopes?.read_summary.map((col: string) => columns.indexOf(col)) || [];

  const copyToClipboard = (row: any, columnNames: string[]) => {{
    const rowString = columnNames.map((col, index) => `${{col}}: ${{row[index]}}`).join('\\n');
    navigator.clipboard.writeText(rowString).then(() => {{
      alert('Row copied to clipboard');
    }}).catch(err => {{
      console.error('Could not copy text: ', err);
    }});
  }};

  return (
    <div className="bg-black border border-yellow-100/30 rounded-lg text-yellow-100 p-4 text-sm">
      <div className="mb-4">
        {{readRoutes.length > 0 && (
          <div className="flex space-x-4">
            {{readRoutes.map((route) => (
              <button
                key={{route}}
                className={{`px-4 py-2 rounded ${{activeTab === route ? 'border-t border-x border-yellow-100/50 rounded-lg' : 'bg-black text-yellow-100/50'}}`}}
                onClick={{() => setActiveTab(route)}}
              >
                {{route}}
              </button>
            ))}}
          </div>
        )}}
      </div>
      <div className="flex justify-between mb-4">
        <div className="flex items-center w-full">
          <SearchInput
            searchInput={{searchInput}}
            handleSearchInputChange={{handleSearchInputChange}}
            searchError={{searchError}}
          />
        </div>
        <button
          className="bg-black border border-yellow-100/30 text-yellow-100/80 hover:bg-yellow-100/80 hover:text-black py-2 px-4 mx-4 rounded-lg text-sm"
          onClick={{() => downloadCSV(filteredData, columns, `${{modal}}_data`)}}
        >
          CSV
        </button>
        {{modalConfig[modal]?.scopes.create && (
          <button
            onClick={{() => setCreateModalOpen(true)}}
            className="bg-black border border-yellow-100/30 text-yellow-100/80 hover:bg-yellow-100/80 hover:text-black py-2 px-4 rounded-lg text-sm"
          >
            Create
          </button>
        )}}
      </div>

      <div className="mb-4 w-fill text-center italic">
        <p>*** Rows Fetched: {{filteredData.length}} ***</p>
      </div>

      <div className="overflow-x-auto h-96">
        <table className="table-fixed min-w-full divide-y divide-yellow-100/30">
          <thead className="bg-black sticky top-0">
            <tr>
              <th className="px-3 py-3 text-left text-xs font-medium text-yellow-100 uppercase tracking-wider">Actions</th>
              {{modalConfig[modal]?.scopes?.read_summary.map((col: string, colIndex: number) => (
                <th
                  key={{`col-${{colIndex}}`}}
                  className="px-3 py-3 text-left text-xs font-medium text-yellow-100 w-96"
                >
                  {{col}}
                </th>
              ))}}
            </tr>
          </thead>
          <tbody>
            {{filteredData.map((row, rowIndex) => (
              <tr key={{`row-${{rowIndex}}`}} className="bg-black text-yellow-100/70 hover:bg-yellow-100/80 hover:text-black">
                <td className="px-3 py-2 break-words text-sm text-gray-300 min-w-64">
                  <button
                    onClick={{() => handleEdit(row, setEditRowData, setEditModalOpen)}}
                    className="bg-black border border-yellow-100/30 text-yellow-100/50 hover:bg-yellow-100/70 hover:text-black hover:border-black py-1 px-2 rounded-lg mr-2"
                  >
                    Edit
                  </button>
                  {{modalConfig[modal]?.scopes.delete && (
                    <button
                      onClick={{() => handleDelete(apiHost as string, modal, row[0], row[1])}}
                      className="bg-black border border-yellow-100/30 text-yellow-100/50 hover:bg-yellow-100/70 hover:text-black hover:border-black py-1 px-2 rounded-lg mr-2"
                    >
                      Delete
                    </button>
                  )}}
                  <button
                    onClick={{() => copyToClipboard(row, modalConfig[modal]?.scopes.read)}}
                    className="bg-black border border-yellow-100/30 text-yellow-100/50 hover:bg-yellow-100/70 hover:text-black hover:border-black py-1 px-2 rounded-lg"
                  >
                    Copy
                  </button>
                </td>
                {{columnIndices.map((colIndex, cellIndex) => {{
                  if (colIndex === -1) return null;
                  const cellValue = row[colIndex];
                  const truncatedValue = typeof cellValue === 'string' && cellValue.length > 250
                    ? `${{cellValue.slice(0, 250)}}...`
                    : cellValue;
                  const isLongCellValue = typeof cellValue === 'string' && cellValue.length > 15;

                  return (
                    <td
                      key={{`cell-${{rowIndex}}-${{cellIndex}}`}}
                      className={{`px-3 py-2 break-words text-sm ${{isLongCellValue ? 'min-w-96' : ''}}`}}
                    >
                      {{typeof truncatedValue === 'string' && isValidUrl(truncatedValue) ? (
                        <button
                          onClick={{() => window.open(truncatedValue, '_blank')}}
                          className="bg-black border border-yellow-100/30 text-yellow-100/50 hover:bg-yellow-100/70 hover:text-black hover:border-black py-1 px-2 rounded-lg"
                        >
                          Open URL
                        </button>
                      ) : (
                        typeof truncatedValue === 'string' && !isNaN(Date.parse(truncatedValue)) ? formatDateTime(truncatedValue) : truncatedValue
                      )}}
                    </td>
                  );
                }})}}
              </tr>
            ))}}
          </tbody>
        </table>
      </div>
      {{isCreateModalOpen && (
        <CreateModal
          modalName={{modal}}
          apiHost={{apiHost as string}}
          columns={{columns}}
          onClose={{() => closeCreateModal(setCreateModalOpen)}}
        />
      )}}
      {{isEditModalOpen && editRowData && (
        <EditModal
          modalName={{modal}}
          apiHost={{apiHost as string}}
          columns={{columns}}
          rowData={{editRowData}}
          onClose={{(updatedData) => closeEditModal(updatedData, columns, setData, setEditModalOpen)}}
        />
      )}}
    </div>
  );
}};

export default DynamicTable;'''

DIR__COMPONENTS__FILE__MODAL_CONFIG__TSX = '''// src/components/modalConfig.tsx
interface Options {{
  [key: string]: string[] | undefined; // Allows any string key with string array or undefined value
}}

interface ConditionalOption {{
  condition: string;
  options: string[];
}}

interface Scopes {{
  create: boolean;
  read: string[];
  read_summary: string[];
  update: string[];
  delete: boolean;
}}

interface ValidationRules {{
  [key: string]: string[];
}}

interface AIQualityChecks {{
  [key: string]: string[];
}}

interface ReadRouteConfig {{
  belongs_to_user_id: boolean;
}}

interface ModalConfig {{
  options: Options;
  conditional_options?: {{
    [key: string]: ConditionalOption[];
  }};
  scopes: Scopes;
  validation_rules: ValidationRules;
  ai_quality_checks: AIQualityChecks;
  read_routes: {{
    [key: string]: ReadRouteConfig;
  }};
}}

interface ModalConfigMap {{
  [key: string]: ModalConfig;
}}



const modalConfig: ModalConfigMap = {{
  "users": {{
    "options": {{
      "type[XOR]": [
        "admin",
        "normal"
      ]
    }},
    "conditional_options": {{}},
    "scopes": {{
      "create": true,
      "read": [
        "id",
        "username",
        "password",
        "type",
        "created_at",
        "updated_at"
      ],
      "read_summary": [
        "id",
        "username",
        "password",
        "type"
      ],
      "update": [
        "username",
        "password",
        "type"
      ],
      "delete": true
    }},
    "validation_rules": {{
      "username": [
        "REQUIRED"
      ],
      "password": [
        "REQUIRED"
      ]
    }},
    "ai_quality_checks": {{}},
    "read_routes": {{
      "default": {{
        "belongs_to_user_id": false
      }}
    }}
  }},
  "router_recovery_outgoing_calls": {{
    "options": {{
      "customer_primary_remarks[XOR]": [
        "ready_to_return",
        "recharge_and_resume",
        "migration_or_shifting",
        "dispute_or_refund",
        "service_issue",
        "already_returned",
        "out_of_town",
        "other"
      ]
    }},
    "conditional_options": {{
      "customer_secondary_remarks": [
        {{
          "condition": "customer_primary_remarks == ready_to_return",
          "options": [
            "disconnect_and_handover",
            "cannot_disconnect_and_handover"
          ]
        }},
        {{
          "condition": "customer_primary_remarks == recharge_and_resume",
          "options": [
            "follow_up_in_24_hours",
            "assign_to_ra"
          ]
        }},
        {{
          "condition": "customer_primary_remarks == migration_or_shifting",
          "options": [
            "shifting_ticket_created",
            "shifting_approved",
            "shifting_denied",
            "shifting_ticket_no_update"
          ]
        }},
        {{
          "condition": "customer_primary_remarks == dispute_or_refund",
          "options": [
            "refund_request_created",
            "refund_approved",
            "refund_denied",
            "refund_request_no_update"
          ]
        }},
        {{
          "condition": "customer_primary_remarks == already_returned",
          "options": [
            "returned_to_lco",
            "returned_to_wiom_official",
            "pata_nahi_kisko_de_diya"
          ]
        }},
        {{
          "condition": "customer_primary_remarks == service_issue",
          "options": [
            "refund_needed",
            "esclataed_to_nqt",
            "other"
          ]
        }},
        {{
          "condition": "customer_primary_remarks == out_of_town",
          "options": [
            "not_applicable"
          ]
        }},
        {{
          "condition": "customer_primary_remarks == other",
          "options": [
            "other"
          ]
        }}
      ]
    }},
    "scopes": {{
      "create": false,
      "read": [
        "id",
        "user_id",
        "belongs_to_user_id",
        "mobile",
        "source",
        "device_id",
        "plan_expiry_date",
        "customer_name",
        "customer_address",
        "zone",
        "lco_contact",
        "pin_code",
        "latitude",
        "longitude",
        "am_name",
        "customer_primary_remarks",
        "customer_secondary_remarks",
        "follow_up_date",
        "comment",
        "created_at",
        "updated_at"
      ],
      "read_summary": [
        "mobile",
        "device_id",
        "customer_name"
      ],
      "update": [
        "category",
        "customer_primary_remarks",
        "customer_secondary_remarks",
        "follow_up_date",
        "comment"
      ],
      "delete": false
    }},
    "validation_rules": {{
      "customer_primary_remarks": [
        "REQUIRED"
      ],
      "customer_secondary_remarks": [
        "REQUIRED"
      ],
      "follow_up_date": [
        "IS_AFTER_TODAY"
      ]
    }},
    "ai_quality_checks": {{}},
    "read_routes": {{
      "uninitiated": {{
        "belongs_to_user_id": true
      }},
      "initiated": {{
        "belongs_to_user_id": true
      }},
      "follow-up-due-today": {{
        "belongs_to_user_id": true
      }},
      "follow-up-overdue": {{
        "belongs_to_user_id": true
      }}
    }}
  }}
}};

export default modalConfig;'''

DIR__COMPONENTS__FILE__DOWNLOAD_UTILS__TSX = '''export const downloadCSV = (data: any[], columns: string[], filename: string) => {{
  const csvRows: string[] = [];
  const headers = columns.join(',');
  csvRows.push(headers);

  const escapeCellValue = (value: any): string => {{
    if (value === null || value === undefined) return '';

    let cellValue = value;
    if (typeof value === 'object') {{
      cellValue = JSON.stringify(value);
    }} else {{
      cellValue = String(value);
    }}

    // Escape double quotes by replacing " with ""
    cellValue = cellValue.replace(/"/g, '""');

    // Enclose the cell in double quotes if it contains a comma, double quotes, or a newline
    if (/[",\\n]/.test(cellValue)) {{
      cellValue = `"${{cellValue}}"`;
    }}

    return cellValue;
  }};

  data.forEach(row => {{
    const values = row.map((cellValue: any) => escapeCellValue(cellValue));
    csvRows.push(values.join(','));
  }});

  const csvContent = "data:text/csv;charset=utf-8," + encodeURIComponent(csvRows.join("\\n"));

  // Get the current timestamp
  const now = new Date();
  const year = now.getFullYear();
  const month = String(now.getMonth() + 1).padStart(2, '0');
  const day = String(now.getDate()).padStart(2, '0');
  const hours = String(now.getHours()).padStart(2, '0');
  const minutes = String(now.getMinutes()).padStart(2, '0');
  const seconds = String(now.getSeconds()).padStart(2, '0');

  const timestamp = `${{year}}${{month}}${{day}}_${{hours}}${{minutes}}${{seconds}}`;
  const timestampedFilename = `${{filename}}_${{timestamp}}.csv`;

  const link = document.createElement('a');
  link.setAttribute('href', csvContent);
  link.setAttribute('download', timestampedFilename);
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}};'''

DIR__COMPONENTS__FILE__QUERY_INPUT__TSX = '''import React from 'react';

interface QueryInputProps {{
  queryInput: string;
  handleQueryInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
  handleQueryKeyPress: (event: React.KeyboardEvent<HTMLInputElement>) => void;
  queryError: string | null;
}}

const QueryInput: React.FC<QueryInputProps> = ({{
  queryInput,
  handleQueryInputChange,
  handleQueryKeyPress,
  queryError,
}}) => {{
  return (
      <input
        type="text"
        value={{queryInput}}
        onChange={{handleQueryInputChange}}
        onKeyPress={{handleQueryKeyPress}}
        placeholder="QUERY MODE (fetches fresh data) ..."
        className="bg-black border border-yellow-100/30 text-yellow-100 px-4 py-2 rounded-lg w-full mx-4 text-sm placeholder-yellow-100/50"
      />
  );
}};

export default QueryInput;'''

DIR__COMPONENTS__FILE__CREATE_MODAL__TSX = '''import React, {{ useState, useCallback, useEffect }} from 'react';
import modalConfig from './modalConfig';
import {{ validateField, open_ai_quality_checks }} from './validationUtils';

interface CreateModalProps {{
  modalName: string;
  apiHost: string;
  columns: string[];
  onClose: () => void;
}}

const CreateModal: React.FC<CreateModalProps> = ({{ modalName, apiHost, columns, onClose }}) => {{
  const [formData, setFormData] = useState<{{ [key: string]: any }}>({{}});
  const [errors, setErrors] = useState<{{ [key: string]: string | null }}>({{}});
  const [dynamicOptions, setDynamicOptions] = useState<{{ [key: string]: string[] }}>({{}});
  const config = modalConfig[modalName];

  useEffect(() => {{
    const initialData = columns.reduce((acc, col) => {{
      acc[col] = '';
      return acc;
    }}, {{}} as {{ [key: string]: any }});
    setFormData(initialData);
  }}, [columns]);

  const evalCondition = useCallback((condition: string) => {{
    const conditionToEvaluate = condition.replace(/(\\w+)/g, (match) => {{
      if (formData.hasOwnProperty(match)) {{
        return `formData['${{match}}']`;
      }}
      return `'${{match}}'`;
    }});
    try {{
      const result = new Function('formData', `return ${{conditionToEvaluate}};`)(formData);
      return result;
    }} catch (e) {{
      console.error('Error evaluating condition:', condition, e);
      return false;
    }}
  }}, [formData]);

  const updateDynamicOptions = useCallback(() => {{
    const newDynamicOptions: {{ [key: string]: string[] }} = {{}};
    if (config.conditional_options) {{
      for (const [field, conditions] of Object.entries(config.conditional_options)) {{
        for (const conditionObj of conditions) {{
          if (evalCondition(conditionObj.condition)) {{
            newDynamicOptions[field] = conditionObj.options;
            break; // Stop checking other conditions if one matches
          }}
        }}
      }}
    }}
    setDynamicOptions(newDynamicOptions);
  }}, [config, evalCondition]);

  useEffect(() => {{
    updateDynamicOptions();
  }}, [updateDynamicOptions]);

  const getCookie = (name: string): string | undefined => {{
    const cookies = document.cookie.split(';').reduce((acc, cookie) => {{
      const [key, value] = cookie.trim().split('=');
      acc[key] = value;
      return acc;
    }}, {{}} as {{ [key: string]: string }});
    return cookies[name];
  }};

  const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {{
    const {{ name, value, type }} = e.target;

    setFormData((prevData) => {{
      if (type === 'checkbox') {{
        if (e.target instanceof HTMLInputElement) {{
          const checked = e.target.checked;
          const currentValues = prevData[name] ? prevData[name].split(';') : [];
          const updatedValues = checked
            ? [...currentValues, value]
            : currentValues.filter((item: string) => item !== value);
          return {{ ...prevData, [name]: updatedValues.join(';') }};
        }}
      }} else {{
        return {{ ...prevData, [name]: value }};
      }}
    }});

    if (config.validation_rules && config.validation_rules[name]) {{
      const error = validateField(name, value, config.validation_rules[name]);
      setErrors((prevErrors) => ({{ ...prevErrors, [name]: error }}));
    }}
  }};

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {{
    e.preventDefault();

    let valid = true;
    const newErrors: {{ [key: string]: string | null }} = {{}};

    if (config.validation_rules) {{
      for (const field of Object.keys(config.validation_rules)) {{
        const error = validateField(field, formData[field], config.validation_rules[field]);
        if (error) {{
          valid = false;
          newErrors[field] = error;
        }}
      }}
    }}

    if (config.ai_quality_checks) {{
      for (const field of Object.keys(config.ai_quality_checks)) {{
        const aiErrors = await open_ai_quality_checks(field, formData[field], config.ai_quality_checks[field]);
        if (aiErrors.length > 0) {{
          valid = false;
          newErrors[field] = aiErrors.join(', ');
        }}
      }}
    }}

    setErrors(newErrors);

    if (!valid) {{
      alert('Please fix the validation errors.');
      return;
    }}

    const user_id = getCookie('user_id');
    if (user_id) {{
      formData['user_id'] = user_id;
    }} else {{
      console.error('User ID not found in cookies');
      onClose();
      return;
    }}

    try {{
      const response = await fetch(`${{apiHost}}create/${{modalName}}`, {{
        method: 'POST',
        headers: {{
          'Content-Type': 'application/json',
        }},
        body: JSON.stringify(formData),
      }});
      const result = await response.json();
      if (result.status === 'success') {{
        alert('Record created successfully');
        onClose();
        window.location.reload();
      }} else {{
        console.error('Failed to create record:', result);
        onClose();
      }}
    }} catch (error) {{
      console.error('Error creating record:', error);
      onClose();
    }}
  }};

  const isFieldEnabled = (field: string) => {{
    if (!config.conditional_options || !config.conditional_options[field]) {{
      return true;
    }}
    return config.conditional_options[field].some((conditionObj: any) => evalCondition(conditionObj.condition));
  }};

  const renderField = (col: string) => {{
    const orTypeOptions = Object.entries(config.options).find(([key]) => key.startsWith(`${{col}}[OR]`));
    const xorTypeOptions = Object.entries(config.options).find(([key]) => key.startsWith(`${{col}}[XOR]`));

    if (orTypeOptions) {{
      return (
        <div className="flex flex-col space-y-2">
          {{orTypeOptions[1]?.map((option: string) => (
            <label key={{option}} className="flex items-center cursor-pointer">
              <input
                type="checkbox"
                name={{col}}
                value={{option}}
                checked={{formData[col]?.split(';').includes(option) || false}}
                onChange={{handleChange}}
                className="h-5 w-5 cursor-pointer appearance-none rounded-md border border-yellow-100/30 transition-all checked:bg-yellow-100/50 checked:border-none"
              />
              <span className="ml-3 text-yellow-100/50">{{option}}</span>
            </label>
          ))}}
        </div>
      );
    }} else if (xorTypeOptions) {{
      return (
        <select
          name={{col}}
          value={{formData[col] || ''}}
          onChange={{handleChange}}
          className="bg-black text-yellow-100/50 px-3 py-2 rounded-lg border border-yellow-100/30 w-full text-sm"
        >
          <option value="" disabled>
            Select {{col}}
          </option>
          {{xorTypeOptions[1]?.map((option: string) => (
            <option key={{option}} value={{option}}>
              {{option}}
            </option>
          ))}}
        </select>
      );
    }} else if (dynamicOptions[col]) {{
      return (
        <select
          name={{col}}
          value={{formData[col] || ''}}
          onChange={{handleChange}}
          className="bg-black text-yellow-100/50 px-3 py-2 rounded-lg border border-yellow-100/30 w-full text-sm"
        >
          <option value="" disabled>
            Select {{col}}
          </option>
          {{dynamicOptions[col]?.map((option: string) => (
            <option key={{option}} value={{option}}>
              {{option}}
            </option>
          ))}}
        </select>
      );
    }} else {{
      return (
        <input
          type="text"
          name={{col}}
          value={{formData[col] || ''}}
          onChange={{handleChange}}
          className="bg-black text-yellow-100/50 px-3 py-2 rounded-lg border border-yellow-100/30 w-full text-sm"
          disabled={{!isFieldEnabled(col)}}
        />
      );
    }}
  }};

  if (!config) {{
    return <div>Loading...</div>;
  }}

  const filteredColumns = config.scopes.create ? columns.filter(column => !['id', 'created_at', 'updated_at', 'user_id'].includes(column)) : [];

  return (
    <div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50 py-4">
      <div className="bg-black border border-yellow-100/30 p-6 rounded-lg w-3/4 max-h-screen overflow-y-auto">
        <h2 className="text-yellow-100/50 text-center mb-8">Create New {{modalName.charAt(0).toUpperCase() + modalName.slice(1)}}</h2>
        <form onSubmit={{handleSubmit}}>
          <div className="grid grid-cols-2 gap-4">
            {{filteredColumns.map((col) => (
              <div key={{col}} className="mb-2">
                <label className="block text-yellow-100/50 ms-1 text-sm">{{col}}</label>
                {{renderField(col)}}
                {{errors[col] && <p className="text-red-500">{{errors[col]}}</p>}}
              </div>
            ))}}
          </div>
          <div className="flex justify-end mt-4">
            <button
              type="button"
              onClick={{onClose}}
              className="bg-black hover:bg-yellow-100/70 text-yellow-100/50 hover:text-black py-1 px-4 rounded-lg text-sm border border-yellow-100/30 hover:border-black mr-2"
            >
              Cancel
            </button>
            <button
              type="submit"
              className="bg-black hover:bg-yellow-100/70 text-yellow-100/50 hover:text-black py-1 px-4 rounded-lg text-sm border border-yellow-100/30 hover:border-black"
            >
              Create
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}};

export default CreateModal;'''

DIR__COMPONENTS__FILE__BULK_OPERATIONS_UTILS__TSX = '''// src/utils/bulkOperationsUtils.ts
import {{ downloadCSV }} from './downloadUtils';
import Papa from 'papaparse';

export async function handleReadOperation(apiHost: string, modal: string, timeLimit: string) {{
  try {{
    const response = await fetch(`${{apiHost}}bulk_read/${{modal}}/${{timeLimit}}`);
    const responseData = await response.json();
    const {{ columns, data }} = responseData;
    downloadCSV(data, columns, 'bulk_read');
  }} catch (error) {{
    console.error('There was an error!', error);
  }}
}}

export async function handleCreateOperation(apiHost: string, modal: string, file: File, userId: string | undefined) {{
  try {{
    const text = await file.text();
    const parsedData = Papa.parse(text, {{ header: true }});
    if (parsedData.errors.length > 0) {{
      console.error('Error parsing CSV file:', parsedData.errors);
      alert('Error parsing CSV File');
      return;
    }}
    if (!parsedData.data || parsedData.data.length === 0) {{
      alert('No data found in the CSV file');
      return;
    }}
    const firstRow = parsedData.data[0];
    if (!firstRow) {{
      alert('The file appears to be empty or improperly formatted.');
      return;
    }}

    // Filter out unwanted columns
    const unwantedColumns = ['id', 'user_id', 'created_at', 'updated_at'];
    const columns = Object.keys(firstRow).filter(col => !unwantedColumns.includes(col));

    // Filter out unwanted data from each row
    const bulkValues = parsedData.data.map((row: any) =>
      columns.map(column => row[column])
    );

    const payload = {{
      user_id: userId,
      columns,
      data: bulkValues,
    }};

    const response = await fetch(`${{apiHost}}bulk_create/${{modal}}`, {{
      method: 'POST',
      headers: {{
        'Content-Type': 'application/json',
      }},
      body: JSON.stringify(payload),
    }});

    const result = await response.json();
    if (response.ok) {{
      alert('Data uploaded successfully');
      window.location.reload();  // Refresh the page on success
    }} else {{
      alert(`Error: ${{result.error}}`);
    }}
  }} catch (error) {{
    console.error('There was an error uploading the data!', error);
    alert('There was an error uploading the data.');
  }}
}}



export async function handleUpdateOperation(apiHost: string, modal: string, file: File | null, userId: string | undefined, selectedColumns: string[]) {{
  if (file) {{
    try {{
      const text = await file.text();
      const parsedData = Papa.parse(text, {{ header: true }});
      if (parsedData.errors.length > 0) {{
        console.error('Error parsing CSV file:', parsedData.errors);
        alert('Error parsing CSV file');
        return;
      }}

      if (!parsedData.data || parsedData.data.length === 0) {{
        alert('No data found in the CSV file');
        return;
      }}

      const firstRow = parsedData.data[0];
      if (!firstRow) {{
        alert('The file appears to be empty or improperly formatted.');
        return;
      }}

      const columns = Object.keys(firstRow);
      selectedColumns.push('id');

      const filteredData = parsedData.data.map((row: any) =>
        selectedColumns.reduce((acc: any, col: string) => {{
          acc[col] = row[col];
          return acc;
        }}, {{}})
      );

      const payload = {{
        user_id: userId,
        columns: selectedColumns,
        data: filteredData // Include the whole row with 'id' field
      }};

      console.log('159');
      console.log(payload);

      const response = await fetch(`${{apiHost}}bulk_update/${{modal}}`, {{
        method: 'PUT', // Use PUT instead of POST
        headers: {{
          'Content-Type': 'application/json',
        }},
        body: JSON.stringify(payload),
      }});

      const result = await response.json();
      if (response.ok) {{
        alert('Data updated successfully');
      }} else {{
        alert(`Error: ${{result.error}}`);
      }}
    }} catch (error) {{
      console.error('There was an error updating the data!', error);
    }}
  }}
}}

export async function handleDeleteOperation(apiHost: string, modal: string, userId: string | undefined, ids: number[]) {{
  if (ids.length > 0 && userId) {{
    try {{
      const payload = {{
        user_id: userId,
        ids: ids,
      }};

      const response = await fetch(`${{apiHost}}bulk_delete/${{modal}}`, {{
        method: 'DELETE',
        headers: {{
          'Content-Type': 'application/json',
        }},
        body: JSON.stringify(payload),
      }});

      const result = await response.json();
      if (response.ok) {{
        alert('Data deleted successfully');
      }} else {{
        alert(`Error: ${{result.error}}`);
      }}
    }} catch (error) {{
      console.error('There was an error deleting the data!', error);
      alert('There was an error deleting the data!');
    }}
  }} else {{
    alert('User ID and IDs to delete are required.');
  }}
}}'''

DIR__COMPONENTS__FILE__SEARCH_INPUT__TSX = '''import React from 'react';

interface SearchInputProps {{
  searchInput: string;
  handleSearchInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
  searchError: string | null;
}}

const SearchInput: React.FC<SearchInputProps> = ({{
  searchInput,
  handleSearchInputChange,
  searchError,
}}) => {{
  return (
    <div className="w-full flex flex-col">
      <input
        type="text"
        value={{searchInput}}
        onChange={{handleSearchInputChange}}
        placeholder="SEARCH MODE (fetches fresh data) ..."
        className="bg-black border border-yellow-100/30 text-yellow-100 px-4 py-2 rounded-lg w-full text-sm placeholder-yellow-100/50"
      />
      {{searchError && <div className="text-red-500 mt-2 text-sm">{{searchError}}</div>}}
    </div>
  );
}};

export default SearchInput;'''

DIR__COMPONENTS__FILE__VALIDATION_UTILS__TSX = '''export const validateField = (field: string, value: any, rules: string[]): string | null => {{
    const isRequired = rules.includes('REQUIRED');

    for (const rule of rules) {{
        const [ruleName, ...params] = rule.split(':');
        switch (ruleName) {{
            case 'REQUIRED':
                if (!value) {{
                    return `${{field}} is required.`;
                }}
                break;
            case 'CHAR_LENGTH':
                const length = parseInt(params[0], 10);
                if (value.length !== length) {{
                    return `${{field}} must be ${{length}} characters long.`;
                }}
                break;
            case 'IS_NUMERICALLY_PARSEABLE':
                if (isNaN(Number(value))) {{
                    return `${{field}} must be numerically parseable.`;
                }}
                break;
            case 'IS_INDIAN_MOBILE_NUMBER':
                if (!isRequired && !value) {{
                    break; // Skip this rule if the field is not required and value is empty
                }}
                const uniqueDigits = new Set(value.split('')).size;
                if (!/^[6789]\\d{{9}}$/.test(value) || uniqueDigits < 4) {{
                    return `${{field}} must be a valid Indian mobile number.`;
                }}
                break;
            case 'IS_YYYY-MM-DD':
                if (!/^\\d{{4}}-\\d{{2}}-\\d{{2}}$/.test(value)) {{
                    return `${{field}} must be in YYYY-MM-DD format.`;
                }}
                break;
            case 'IS_AFTER_TODAY':
                if (!isRequired && !value) {{
                    break; // Skip this rule if the field is not required and value is empty
                }}
                if (!/^\\d{{4}}-\\d{{2}}-\\d{{2}}$/.test(value)) {{
                    return `${{field}} must be in YYYY-MM-DD format.`;
                }}
                if (new Date(value) <= new Date(new Date().toDateString())) {{ // Ensure only the date part is compared
                    return `${{field}} must be a date after today.`;
                }}
                break;
            case 'IS_BEFORE_TODAY':
                if (!isRequired && !value) {{
                    break; // Skip this rule if the field is not required and value is empty
                }}
                if (!/^\\d{{4}}-\\d{{2}}-\\d{{2}}$/.test(value)) {{
                    return `${{field}} must be in YYYY-MM-DD format.`;
                }}
                if (new Date(value) >= new Date(new Date().toDateString())) {{ // Ensure only the date part is compared
                    return `${{field}} must be a date before today.`;
                }}
                break;
            // Add more validation rules as needed
            default:
                break;
        }}
    }}
    return null;
}};

const OPEN_AI_KEY = process.env.NEXT_PUBLIC_OPEN_AI_KEY;
const OPEN_AI_MODEL = process.env.NEXT_PUBLIC_OPEN_AI_JSON_MODE_MODEL;

export const open_ai_quality_checks = async (field: string, value: string, checks: string[]): Promise<string[]> => {{
  const failedChecks: string[] = [];

  if (!OPEN_AI_KEY) {{
    console.error("OpenAI API key is not set");
    return ["OpenAI API key is not set"];
  }}

  for (const check of checks) {{
    const prompt = `
    Your only job is to ascertain if the user's input meets this criterion '${{check}}' and output a boolean true or false, as JSON in this format {{"evaluation": "true"}}.
    `;

    try {{
      const response = await fetch('https://api.openai.com/v1/chat/completions', {{
        method: 'POST',
        headers: {{
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${{OPEN_AI_KEY}}`
        }},
        body: JSON.stringify({{
          model: OPEN_AI_MODEL,
          messages: [
            {{
              role: 'system',
              content: prompt
            }},
            {{
              role: 'user',
              content: value
            }}
          ]
        }})
      }});

      const data = await response.json();
      const aiResult = data.choices[0].message.content;
      const evaluation = JSON.parse(aiResult).evaluation;

      if (evaluation !== "true") {{
        failedChecks.push(`${{field}} does not meet the criterion: ${{check}}`);
      }}
    }} catch (error) {{
      console.error('Error during OpenAI API call:', error);
      if (error instanceof Error) {{
        failedChecks.push(`Error evaluating ${{check}}: ${{error.message}}`);
      }} else {{
        failedChecks.push(`Error evaluating ${{check}}: ${{String(error)}}`);
      }}
    }}
  }}

  return failedChecks;
}};'''

DIR__COMPONENTS__FILE__SIDEBAR__TSX = '''// src/components/Sidebar.tsx

import React, {{ useEffect, useCallback, useState }} from 'react';
import Link from 'next/link';
import {{ useRouter }} from 'next/router';
import modalConfig from './modalConfig';

interface Cookies {{
  [key: string]: string;
}}

const parseCookies = (): Cookies => {{
  return document.cookie.split(';').reduce((acc: Cookies, cookie) => {{
    const [key, value] = cookie.trim().split('=');
    acc[key] = value;
    return acc;
  }}, {{}});
}};

const Sidebar: React.FC = () => {{
  const [cookies, setCookies] = useState<Cookies>({{}});
  const [userType, setUserType] = useState<string>('');
  const [userName, setUserName] = useState<string>('');
  const [userId, setUserId] = useState<string>('');

  const modals = Object.keys(modalConfig);

  const filteredModals = modals.filter(modal => {{
    if (modal === 'users' && userType !== 'admin' && userType !== 'sudo') {{
      return false;
    }}
    return true;
  }});

  const router = useRouter();

  const handleLogout = useCallback(() => {{
    document.cookie = 'user_id=; Max-Age=0; path=/';
    document.cookie = 'auth=; Max-Age=0; path=/';
    document.cookie = 'username=; Max-Age=0; path=/';
    document.cookie = 'type=; Max-Age=0; path=/';
    router.push('/login');
  }}, [router]);

  const handleBulkOperationsClick = () => {{
    router.push('/bulk_operations');
  }};

  useEffect(() => {{
    if (typeof window !== 'undefined') {{
      const parsedCookies = parseCookies();
      setCookies(parsedCookies);
      setUserType(parsedCookies.type);
      setUserName(parsedCookies.username);
      setUserId(parsedCookies.user_id);

      if (!parsedCookies.user_id) {{
        handleLogout();
      }}
    }}
  }}, [handleLogout]);

  const apkUrl = process.env.NEXT_PUBLIC_APK_URL;

  return (
    <div className="bg-black border-r border-yellow-100/25 text-yellow-100/70 w-64 min-h-screen p-4 flex flex-col">
      <div className="flex-grow">
        <h1 className="text text-yellow-100/50 ml-1 mt-4">Chemical-X</h1>
         <hr className="border-yellow-100/10 my-4"/>
        <ul>
          {{filteredModals.map((item) => (
            <li key={{item}} className="text-sm mb-1 p-1 text-yellow-100/50 rounded-lg bg-black border border-yellow-100/10 hover:bg-yellow-100/70 hover:text-black">
              <Link href={{`/${{item}}`}} legacyBehavior>
                <a className="block w-full h-full ps-1 cursor-pointer">
                  {{item}}
                </a>
              </Link>
            </li>
          ))}}
        </ul>
        <hr className="border-yellow-100/10 my-4"/>
        {{userType === 'admin' || userType === 'sudo' ? (
          <button
            onClick={{handleBulkOperationsClick}}
            className="text-sm mb-1 p-1 text-yellow-100/50 rounded-lg bg-black border border-yellow-100/10 hover:bg-yellow-100/70 hover:text-black w-full text-left"
          >
            bulk_operations
          </button>
        ) : null}}
        <a
          className="block text-sm mb-1 p-1 text-yellow-100/50 rounded-lg bg-black border border-yellow-100/10 hover:bg-yellow-100/70 hover:text-black text-left"
          href={{apkUrl}}
          download
        >
          download_android_app
        </a>
        <button
          onClick={{handleLogout}}
          className="text-sm mb-1 p-1 text-yellow-100/50 rounded-lg bg-black border border-yellow-100/10 hover:bg-yellow-100/70 hover:text-black w-full text-left"
        >
          logout_{{userName}}_[{{userId}},{{userType}}]
        </button>
      </div>
    </div>
  );
}};

export default Sidebar;'''

DIR__COMPONENTS__FILE__QUERY_UTILS__TSX = '''export const handleQuerySubmit = async (
  apiHost: string,
  modal: string,
  queryInput: string,
  setData: React.Dispatch<React.SetStateAction<any[]>>,
  setQueryError: React.Dispatch<React.SetStateAction<string | null>>
) => {{
  try {{
    const response = await fetch(`${{apiHost}}query/${{modal}}`, {{
      method: 'POST',
      headers: {{
        'Content-Type': 'application/json',
      }},
      body: JSON.stringify({{ query_string: queryInput.trim() }}),
    }});
    const result = await response.json();
    if (response.ok) {{
      setData(result.data);
      setQueryError(null);
    }} else {{
      console.error('Error fetching query results:', result);
      setQueryError(result.error || 'Unknown error occurred');
    }}
  }} catch (error) {{
    console.error('Error fetching query results:', error);
    if (error instanceof Error) {{
      setQueryError(error.message || 'Unknown error occurred');
    }} else {{
      setQueryError('Unknown error occurred');
    }}
  }}
}};'''

DIR__COMPONENTS__FILE__BULK_OPERATIONS__TSX = '''import React, {{ useEffect, useState }} from 'react';
import modalConfig from './modalConfig';
import {{ downloadCSV }} from './downloadUtils';
import {{ getUserIDFromCookies }} from './crudUtils';
import {{ handleReadOperation, handleCreateOperation, handleUpdateOperation, handleDeleteOperation }} from './bulkOperationsUtils';
import Papa from 'papaparse';

const BulkOperationsForm: React.FC = () => {{
  const apiHost = process.env.NEXT_PUBLIC_API_HOST;

  const [userId, setUserId] = useState<string | undefined>(undefined);
  const [operation, setOperation] = useState<string>('');
  const [modal, setModal] = useState<string>('');
  const [timeLimit, setTimeLimit] = useState<string>('');
  const [file, setFile] = useState<File | null>(null);
  const [columns, setColumns] = useState<string[]>([]);
  const [selectedColumns, setSelectedColumns] = useState<string[]>([]);
  const [isColumnSelectionVisible, setIsColumnSelectionVisible] = useState<boolean>(false);
  const [isValidFile, setIsValidFile] = useState<boolean>(true);  // State to manage file validity


  useEffect(() => {{
    setUserId(getUserIDFromCookies());
  }}, []);

  useEffect(() => {{
    const parseFile = async () => {{
      if (file) {{
        const text = await file.text();
        const parsedData = Papa.parse(text, {{ header: true }});
        if (parsedData.errors.length > 0) {{
          console.error('Error parsing CSV file:', parsedData.errors);
          alert('Error parsing CSV File');
          setIsValidFile(false);
          return;
        }}
        if (!parsedData.data || parsedData.data.length === 0) {{
          alert('No data found in the CSV file');
          setIsValidFile(false);
          return;
        }}
        const firstRow = parsedData.data[0];
        if (!firstRow) {{
          alert('The file appears to be empty or improperly formatted.');
          setIsValidFile(false);
          return;
        }}

        const cols = Object.keys(firstRow).filter(col => !['user_id', 'created_at', 'updated_at'].includes(col));

        // Get the read scope columns for the selected modal
        const readScopeColumns = modalConfig[modal]?.scopes?.read || [];

        console.log(readScopeColumns);
        console.log(cols);

        // Check if every column in the file is in the read scope
        const isValidFile = cols.every(col => readScopeColumns.includes(col));

        if (!isValidFile) {{
          setIsValidFile(false);
          return;
        }}

        setColumns(cols);
        setIsColumnSelectionVisible(true);
        setIsValidFile(true);
      }}
    }};

    if (operation === 'update' && file) {{
      parseFile();
    }}
  }}, [file, operation, modal]);

  const modalNames = Object.keys(modalConfig);
  const timeLimits = [
    'today',
    'since_yesterday',
    'since_last_7_days',
    'since_last_14_days',
    'since_last_28_days',
    'since_last_90_days',
  ];

  const validateForm = (): string[] => {{
    const missingFields: string[] = [];
    if (operation === '') missingFields.push('operation');
    if (modal === '') missingFields.push('modal');
    if (operation === 'read' && timeLimit === '') missingFields.push('time_limit');
    return missingFields;
  }};

const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {{
  event.preventDefault();

  const missingFields = validateForm();
  if (missingFields.length > 0) {{
    alert(`Please fill all required fields: ${{missingFields.join(', ')}}`);
    return;
  }}

  if (!isValidFile) {{
    alert('The file uploaded does not relate to the modal selected.');
    return;
  }}

  // Ensure the apiHost, modal, and timeLimit are non-null, non-undefined strings
  if (!apiHost || !modal) {{
    alert('API host and modal must be selected.');
    return;
  }}

  try {{
    if (operation === 'read') {{
      await handleReadOperation(apiHost, modal, timeLimit || '');
    }} else if (operation === 'create') {{
      if (file) {{
        await handleCreateOperation(apiHost, modal, file, userId);
        window.location.reload();
      }} else {{
        alert('Please upload a file.');
      }}
    }} else if (operation === 'update') {{
      if (isColumnSelectionVisible && selectedColumns.length > 0) {{
        // Proceed with the update operation
        await handleUpdateOperation(apiHost, modal, file, userId, selectedColumns);
        window.location.reload();
      }} else {{
        alert('Please select columns to update.');
      }}
    }} else if (operation === 'delete') {{
      if (file) {{
        // Parse the file to extract ids
        const text = await file.text();
        const parsedData = Papa.parse(text, {{ header: true }});
        if (parsedData.errors.length > 0) {{
          console.error('Error parsing CSV file:', parsedData.errors);
          alert('Error parsing CSV file');
          return;
        }}
        if (!parsedData.data || parsedData.data.length === 0) {{
          alert('No data found in the CSV file');
          return;
        }}
        const ids = parsedData.data.map((row: any) => parseInt(row['id'], 10)).filter((id: number) => !isNaN(id));
        if (ids.length === 0) {{
          alert('No valid IDs found in the CSV file');
          return;
        }}

        await handleDeleteOperation(apiHost, modal, userId || '', ids);
        window.location.reload();
      }} else {{
        alert('Please upload a file.');
      }}
    }} else {{
      alert('Form submitted successfully.');
    }}
  }} catch (error) {{
    console.error('There was an error handling the operation!', error);
    alert('There was an error handling the operation.');
  }}
}};


  const handleDownloadTemplate = () => {{
    const columns = modalConfig[modal].scopes.read.filter(
      column => column !== 'id' && column !== 'user_id' && column !== 'created_at' && column !== 'updated_at'
    );
    downloadCSV([], columns, `${{modal}}_create_template`);
  }};

  const handleColumnSelectionChange = (column: string) => {{
    setSelectedColumns((prev) =>
      prev.includes(column) ? prev.filter(col => col !== column) : [...prev, column]
    );
  }};

  return (
    <form onSubmit={{handleSubmit}}>
      <div className="mb-4">
        <label htmlFor="operation" className="block text-sm text-yellow-100/50 mb-2">operation</label>
        <select
          id="operation"
          value={{operation}}
          onChange={{(e) => setOperation(e.target.value)}}
          className="block w-full p-2.5 bg-black border border-yellow-100/30 rounded-lg text-yellow-100/50"
        >
          <option value="" disabled></option>
          <option value="create">create</option>
          <option value="read">read</option>
          <option value="update">update</option>
          <option value="delete">delete</option>
        </select>
      </div>

      <div className="mb-4">
        <label htmlFor="modal" className="block text-sm text-yellow-100/50 mb-2">modal</label>
        <select
          id="modal"
          value={{modal}}
          onChange={{(e) => setModal(e.target.value)}}
          className="block w-full p-2.5 bg-black border border-yellow-100/30 rounded-lg text-yellow-100/50"
        >
          <option value="" disabled></option>
          {{modalNames.map((modalName) => (
            <option key={{modalName}} value={{modalName}}>{{modalName}}</option>
          ))}}
        </select>
      </div>

      {{operation === 'read' && (
        <div className="mb-4">
          <label htmlFor="timeLimit" className="block text-sm text-yellow-100/50 mb-2">time_limit</label>
          <select
            id="timeLimit"
            value={{timeLimit}}
            onChange={{(e) => setTimeLimit(e.target.value)}}
            className="block w-full p-2.5 bg-black border border-yellow-100/30 rounded-lg text-yellow-100/50"
          >
            <option value="" disabled>Select a time limit</option>
            {{timeLimits.map((limit) => (
              <option key={{limit}} value={{limit}}>{{limit}}</option>
            ))}}
          </select>
        </div>
      )}}

      {{operation === 'create' && modal && (
        <div className="mb-4">
          <button
            type="button"
            onClick={{handleDownloadTemplate}}
            className="bg-black text-yellow-100/50 border border-yellow-100/30 hover:bg-yellow-100 hover:text-black py-2 px-6 rounded-lg"
          >
            Download Template
          </button>
        </div>
      )}}

      {{(operation === 'create' || operation === 'update' || operation === 'delete') && (
        <div className="mb-4">
          <label htmlFor="file" className="block text-sm text-yellow-100/50 mb-2">upload_csv</label>
          <input
            type="file"
            id="file"
            onChange={{(e) => setFile(e.target.files ? e.target.files[0] : null)}}
            className="block w-full text-yellow-100/50 bg-black border border-yellow-100/30 rounded-lg p-2.5"
          />
        </div>
      )}}


{{isColumnSelectionVisible && (
  <div className="flex flex-col space-y-2 mb-4">
    <label className="block text-sm text-yellow-100/50 mb-2">confirm_columns_to_update</label>
    {{columns.filter(column => column !== 'id').map((filteredColumn) => (
      <label key={{filteredColumn}} className="flex items-center cursor-pointer">
        <input
          type="checkbox"
          id={{filteredColumn}}
          value={{filteredColumn}}
          onChange={{() => handleColumnSelectionChange(filteredColumn)}}
          checked={{selectedColumns.includes(filteredColumn)}}
          className="h-5 w-5 cursor-pointer appearance-none rounded-md border border-yellow-100/30 transition-all checked:bg-yellow-100/50 checked:border-none"
        />
        <span className="ml-3 text-yellow-100/50">{{filteredColumn}}</span>
      </label>
    ))}}
  </div>
)}}


      <div className="text-right">
        <button
          type="submit"
          className="bg-yellow-100 text-black py-2.5 px-6 rounded-lg mt-4"
          disabled={{operation === 'update' && isColumnSelectionVisible && selectedColumns.length === 0}}
        >
          Submit
        </button>
      </div>
    </form>
  );
}};

export default BulkOperationsForm;'''

DIR__PAGES__FILE__BULK__OPERATIONS__TSX = '''// pages/bulk_operations.tsx
import React from 'react';
import Sidebar from '../components/Sidebar';
import BulkOperationsForm from '../components/BulkOperations';
import '../app/globals.css';

const BulkOperationsPage: React.FC = () => {{
  return (
    <div className="flex">
      <Sidebar />
      <div className="bg-black min-h-screen flex-1 p-8 overflow-x-auto">
        <div className="container mx-auto">
          <h1 className="text-yellow-100/50 mr-2 text-right">bulk_operations</h1>
          <div className="bg-black border border-yellow-100/30 rounded-lg text-yellow-100 p-4 text-sm flex justify-center">
            <div className="w-96 max-w-xl">
              <BulkOperationsForm />
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}};

export default BulkOperationsPage;'''

DIR__PAGES__FILE__LOGIN__TSX = '''import React, {{ useState }} from 'react';
import {{ useRouter }} from 'next/navigation';
import '../app/globals.css';


const isAuthenticated = () => {{
  const cookies = document.cookie.split(';').reduce((acc: {{ [key: string]: string }}, cookie) => {{
    const [key, value] = cookie.trim().split('=');
    acc[key] = value;
    return acc;
  }}, {{}} as {{ [key: string]: string }});

  return cookies.user_id !== undefined;
}};


const LoginPage: React.FC = () => {{
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');
  const router = useRouter();
  const apiHost = process.env.NEXT_PUBLIC_API_HOST;

  const handleSubmit = async (e: React.FormEvent) => {{
    e.preventDefault();

    if (isAuthenticated()) {{
      router.push('/');
      return;
    }}

    try {{
      const response = await fetch(`${{apiHost}}authenticate`, {{
        method: 'POST',
        headers: {{
          'Content-Type': 'application/json',
        }},
        body: JSON.stringify({{ username, password }}),
      }});

      const result = await response.json();
      console.log(result); // Debugging: Log the result
      if (result.status === 'success') {{
        // Set cookie for authentication
        const user = result.user;
        document.cookie = `user_id=${{user.id}}; path=/`;
	document.cookie = `username=${{user.username}}; path=/`;
	document.cookie = `type=${{user.type}}; path=/`;
        document.cookie = `auth=true; path=/`;
        console.log("Authentication successful, redirecting..."); // Debugging: Log before redirect
        router.push('/');
      }} else {{
        setError(result.message);
      }}
    }} catch (error) {{
      console.error("Error during authentication:", error);
      setError("An error occurred during authentication. Please try again.");
    }}
  }};

  return (
    <div className="min-h-screen bg-black text-yellow-100/50 flex items-center justify-center">
      <div className="border border-yellow-100/30 p-7 rounded-lg shadow-lg w-96">
        <h2 className="mb-4 text-center font-bold animate-pulse">Chemical-X</h2>
        <form onSubmit={{handleSubmit}}>
          <div className="mb-4">
            <label className="block text-sm text-yellow-100/50 ml-1">Username</label>
            <input
              type="text"
              name="username"
              value={{username}}
              onChange={{(e) => setUsername(e.target.value)}}
              className="bg-black p-2 rounded-lg w-full border border-yellow-100/30 text-sm"
              required
            />
          </div>
          <div className="mb-2">
            <label className="block text-sm text-yellow-100/50 ml-1">Password</label>
            <input
              type="password"
              name="password"
              value={{password}}
              onChange={{(e) => setPassword(e.target.value)}}
              className="bg-black p-2 rounded-lg w-full border border-yellow-100/30 text-sm"
              required
            />
          </div>
          {{error && <p className="text-red-500 mb-2">{{error}}</p>}}
          <div className="flex justify-end mt-8">
            <button
              type="submit"
              className="bg-black hover:bg-yellow-100/50 text-yellow-100/50 hover:text-black py-2 px-4 rounded-lg text-sm border border-yellow-100/30 hover:border-black"
            >
              Login
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}};

export default LoginPage;'''

DIR__PAGES__FILE____MODAL____TSX = '''import React, {{ useEffect, useState }} from 'react';
import {{ useRouter }} from 'next/router';
import DynamicTable from '../components/DynamicTable';
import Sidebar from '../components/Sidebar';
import '../app/globals.css';

const ModalPage: React.FC = () => {{
  const router = useRouter();
  const {{ modal }} = router.query;


  return (
    <div className="flex">
      <Sidebar />
      <div className="bg-black min-h-screen flex-1 p-8 overflow-x-auto">
        <div className="container mx-auto">
          <h1 className="text-yellow-100/50 mr-2 text-right">
            {{(modal as string)}} table
          </h1>
            <DynamicTable
              modal={{modal as string}}
            />
        </div>
      </div>
    </div>
  );
}};

export default ModalPage;'''

DIR__STYLES__FILE__SCROLLBAR__CSS = '''/* styles/scrollbar.css */

/* Custom Scrollbar Styles */
::-webkit-scrollbar {{
  width: 12px;
  height: 12px;
}}

::-webkit-scrollbar-thumb {{
  background-color: #fef9c3; /* Yellow */
  border-radius: 6px;
  border: 3px solid #000000; /* Black border */
}}

::-webkit-scrollbar-thumb:hover {{
  background-color: #fde047; /* Darker yellow on hover */
}}

::-webkit-scrollbar-track {{
  background-color: #000000; /* Black */
  border-radius: 6px;
}}

body {{
  scrollbar-color: #fef9c3 #000000; /* Yellow thumb and black track for Firefox */
  scrollbar-width: thin;
}}'''

ROOT__FILE__MIDDLEWARE__TSX = '''import {{ NextResponse }} from 'next/server';
import type {{ NextRequest }} from 'next/server';

export function middleware(request: NextRequest) {{
  const user_id = request.cookies.get('user_id');

  if (!user_id && request.nextUrl.pathname !== '/login') {{
    return NextResponse.redirect(new URL('/login', request.url));
  }}

  if (user_id && request.nextUrl.pathname === '/login') {{
    return NextResponse.redirect(new URL('/', request.url));
  }}

  return NextResponse.next();
}}

export const config = {{
  matcher: ['/', '/login','/users','/customers','/partners'],
}};'''
