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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/a.txt

This file was deleted.

83 changes: 62 additions & 21 deletions src/components/DynamicInvoiceForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
IonItemDivider,
IonTextarea,
IonChip,
IonAlert,
} from "@ionic/react";
import {
close,
Expand Down Expand Up @@ -55,14 +56,15 @@ const DynamicInvoiceForm: React.FC<DynamicInvoiceFormProps> = ({
isOpen,
onClose,
}) => {
const { activeTemplateData, currentSheetId } = useInvoice();
const { activeTemplateData, currentSheetId, selectedFile } = useInvoice();
const [formData, setFormData] = useState<ProcessedFormData>({});
const [showToast, setShowToast] = useState(false);
const [toastMessage, setToastMessage] = useState("");
const [toastColor, setToastColor] = useState<
"success" | "danger" | "warning"
>("success");
const [lastSyncTime, setLastSyncTime] = useState<number>(0);
const [showRefreshAlert, setShowRefreshAlert] = useState(false);

// Get current template data
const currentTemplate = useMemo(() => {
Expand Down Expand Up @@ -128,7 +130,7 @@ const DynamicInvoiceForm: React.FC<DynamicInvoiceFormProps> = ({
useEffect(() => {
if (isOpen && formSections.length > 0) {
const timeoutId = setTimeout(() => {
handleRefresh();
silentRefresh();
}, 200);

return () => clearTimeout(timeoutId);
Expand Down Expand Up @@ -263,7 +265,34 @@ const DynamicInvoiceForm: React.FC<DynamicInvoiceFormProps> = ({
}
};

const handleRefresh = async () => {
const silentRefresh = async () => {
try {
// Get all cell references from the form sections
const cellReferences =
DynamicFormManager.getAllCellReferences(formSections);

if (cellReferences.length > 0) {
console.log("Silently refreshing data from cells:", cellReferences);

// Get current data from the spreadsheet
const currentCellData = await getDynamicInvoiceData(cellReferences);

// Convert cell data back to form data structure
const refreshedFormData =
DynamicFormManager.convertFromSpreadsheetFormat(
currentCellData,
formSections
);

console.log("Silent refresh - form data updated:", refreshedFormData);
setFormData(refreshedFormData);
}
} catch (error) {
console.error("Error during silent refresh:", error);
}
};

const performRefresh = async () => {
try {
// Get all cell references from the form sections
const cellReferences =
Expand Down Expand Up @@ -294,6 +323,10 @@ const DynamicInvoiceForm: React.FC<DynamicInvoiceFormProps> = ({
}
};

const handleRefresh = () => {
setShowRefreshAlert(true);
};

const handleAddItem = (sectionTitle: string) => {
const section = formSections.find((s) => s.title === sectionTitle);
if (!section || !section.itemsConfig) return;
Expand All @@ -318,11 +351,6 @@ const DynamicInvoiceForm: React.FC<DynamicInvoiceFormProps> = ({
[sectionTitle]: [...currentItems, newItem],
};
});

// Trigger save after state update (but don't close modal)
setTimeout(() => {
saveToSheet();
}, 100);
};

const handleRemoveItem = (sectionTitle: string, itemIndex: number) => {
Expand All @@ -344,11 +372,6 @@ const DynamicInvoiceForm: React.FC<DynamicInvoiceFormProps> = ({

return newFormData;
});

// Trigger save after state update (but don't close modal)
setTimeout(() => {
saveToSheet();
}, 100);
};

const renderField = (field: DynamicFormField, sectionTitle: string) => {
Expand Down Expand Up @@ -529,7 +552,7 @@ const DynamicInvoiceForm: React.FC<DynamicInvoiceFormProps> = ({
<IonModal isOpen={isOpen} onDidDismiss={onClose}>
<IonHeader>
<IonToolbar color="primary">
<IonTitle>Dynamic Invoice Form</IonTitle>
<IonTitle>Edit {selectedFile}</IonTitle>
<IonButtons slot="end">
<IonButton onClick={onClose}>
<IonIcon icon={close} />
Expand All @@ -555,13 +578,7 @@ const DynamicInvoiceForm: React.FC<DynamicInvoiceFormProps> = ({
>
<IonHeader>
<IonToolbar color="primary">
<IonTitle>Dynamic Invoice Form</IonTitle>
<IonButtons slot="start">
<IonChip>
<IonIcon icon={layers} />
<IonLabel>{currentTemplate.template}</IonLabel>
</IonChip>
</IonButtons>
<IonTitle>Edit {selectedFile}</IonTitle>
<IonButtons slot="end">
<IonButton onClick={handleRefresh} fill="clear">
<IonIcon icon={refresh} />
Expand Down Expand Up @@ -614,6 +631,30 @@ const DynamicInvoiceForm: React.FC<DynamicInvoiceFormProps> = ({
duration={3000}
color={toastColor}
/>

<IonAlert
isOpen={showRefreshAlert}
onDidDismiss={() => setShowRefreshAlert(false)}
header="Sync Sheet Data"
message="Do you want to sync sheet data to the form? This will discard any changes you might have made."
buttons={[
{
text: "Cancel",
role: "cancel",
handler: () => {
setShowRefreshAlert(false);
},
},
{
text: "Sync Data",
role: "confirm",
handler: () => {
setShowRefreshAlert(false);
performRefresh();
},
},
]}
/>
</>
);
};
Expand Down
91 changes: 58 additions & 33 deletions src/components/Files/Files.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ const Files: React.FC<{

const [serverFilesLoading, setServerFilesLoading] = useState(false);

// Template selection states
const [selectedTemplateFilter, setSelectedTemplateFilter] = useState<
number | "all"
// Template selection states - now using category instead of specific template
const [selectedCategoryFilter, setSelectedCategoryFilter] = useState<
string | "all"
>("all");

// Screen size state
Expand All @@ -125,6 +125,31 @@ const Files: React.FC<{
}));
};

// Category helper functions
const categorizeTemplate = (template_id: number) => {
const metadata = tempMeta.find((meta) => meta.template_id === template_id);
if (!metadata?.category) return "web";

const category = metadata.category.toLowerCase();
if (category === "mobile") {
return "mobile";
} else if (category === "tablet") {
return "tablet";
} else {
return "web";
}
};

const getAvailableCategories = () => {
const categories = new Set<string>();
tempMeta.forEach((template) => {
if (template.category) {
categories.add(template.category);
}
});
return Array.from(categories).sort();
};

const getTemplateInfo = (templateId: number) => {
const template = DATA[templateId];
return template ? template.template : `Template ${templateId}`;
Expand Down Expand Up @@ -456,12 +481,16 @@ const Files: React.FC<{
};
});

// Filter by template if a specific template is selected
// Filter by category if a specific category is selected
let filteredFiles = filesArray;
if (selectedTemplateFilter !== "all") {
filteredFiles = filesArray.filter(
(file) => file.templateMetadata?.templateId === selectedTemplateFilter
);
if (selectedCategoryFilter !== "all") {
filteredFiles = filesArray.filter((file) => {
if (!file.templateMetadata?.templateId) return false;
const templateCategory = categorizeTemplate(
file.templateMetadata.templateId
);
return templateCategory === selectedCategoryFilter.toLowerCase();
});
}

// Apply search filter
Expand All @@ -470,10 +499,8 @@ const Files: React.FC<{
if (filteredFiles.length === 0) {
const emptyMessage = searchQuery.trim()
? `No files found matching "${searchQuery}"`
: selectedTemplateFilter !== "all"
? `No files found for ${getTemplateInfo(
selectedTemplateFilter as number
)}`
: selectedCategoryFilter !== "all"
? `No files found for ${selectedCategoryFilter} category`
: "No local files found";

content = (
Expand Down Expand Up @@ -690,7 +717,7 @@ const Files: React.FC<{
searchQuery,
sortBy,
serverFilesLoading,
selectedTemplateFilter,
selectedCategoryFilter,
]);

// Check screen size
Expand Down Expand Up @@ -749,7 +776,7 @@ const Files: React.FC<{
style={{ flex: "2", minWidth: "200px" }}
/>

{/* Template Filter */}
{/* Category Filter */}
<div
style={{
display: "flex",
Expand All @@ -768,10 +795,10 @@ const Files: React.FC<{
/>
{!isSmallScreen && (
<IonSelect
value={selectedTemplateFilter}
placeholder="All Templates"
value={selectedCategoryFilter}
placeholder="All Categories"
onIonChange={(e) =>
setSelectedTemplateFilter(e.detail.value)
setSelectedCategoryFilter(e.detail.value)
}
style={{
flex: "1",
Expand All @@ -780,23 +807,22 @@ const Files: React.FC<{
}}
interface="popover"
>
<IonSelectOption value="all">All Templates</IonSelectOption>
{getAvailableTemplates().map((template) => (
<IonSelectOption
key={template.templateId}
value={template.templateId}
>
{template.template}
<IonSelectOption value="all">
All Categories
</IonSelectOption>
{getAvailableCategories().map((category) => (
<IonSelectOption key={category} value={category}>
{category}
</IonSelectOption>
))}
</IonSelect>
)}
{isSmallScreen && (
<IonSelect
value={selectedTemplateFilter}
value={selectedCategoryFilter}
placeholder=""
onIonChange={(e) =>
setSelectedTemplateFilter(e.detail.value)
setSelectedCategoryFilter(e.detail.value)
}
style={{
flex: "1",
Expand All @@ -807,13 +833,12 @@ const Files: React.FC<{
}}
interface="popover"
>
<IonSelectOption value="all">All Templates</IonSelectOption>
{getAvailableTemplates().map((template) => (
<IonSelectOption
key={template.templateId}
value={template.templateId}
>
{template.template}
<IonSelectOption value="all">
All Categories
</IonSelectOption>
{getAvailableCategories().map((category) => (
<IonSelectOption key={category} value={category}>
{category}
</IonSelectOption>
))}
</IonSelect>
Expand Down
30 changes: 14 additions & 16 deletions src/components/TemplateModal/TemplateModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,15 @@ const TemplateModal: React.FC<TemplateModalProps> = ({
return tempMeta.find((meta) => meta.template_id === templateId);
};

// Categorize templates based on their names
const categorizeTemplate = (templateName: string | undefined) => {
if (!templateName) return "web";
const name = templateName.toLowerCase();
if (name.includes("mobile")) {
// Categorize templates based on their metadata category
const categorizeTemplate = (template_id: number) => {
const metadata = getTemplateMetadata(template_id);
if (!metadata?.category) return "web";

const category = metadata.category.toLowerCase();
if (category === "mobile") {
return "mobile";
} else if (name.includes("tablet")) {
} else if (category === "tablet") {
return "tablet";
} else {
return "web";
Expand All @@ -90,19 +92,13 @@ const TemplateModal: React.FC<TemplateModalProps> = ({
const templates = tempMeta;
const categorized = {
web: templates.filter((t) => {
const metadata = getTemplateMetadata(t.template_id);
const templateName = metadata?.name || t.name || "Unknown Template";
return categorizeTemplate(templateName) === "web";
return categorizeTemplate(t.template_id) === "web";
}),
mobile: templates.filter((t) => {
const metadata = getTemplateMetadata(t.template_id);
const templateName = metadata?.name || t.name || "Unknown Template";
return categorizeTemplate(templateName) === "mobile";
return categorizeTemplate(t.template_id) === "mobile";
}),
tablet: templates.filter((t) => {
const metadata = getTemplateMetadata(t.template_id);
const templateName = metadata?.name || t.name || "Unknown Template";
return categorizeTemplate(templateName) === "tablet";
return categorizeTemplate(t.template_id) === "tablet";
}),
};
return categorized;
Expand Down Expand Up @@ -257,7 +253,9 @@ const TemplateModal: React.FC<TemplateModalProps> = ({
template.template ||
template.name ||
"Unknown Template";
const category = categorizeTemplate(templateName);
const category = categorizeTemplate(
template.templateId || template.template_id
);

// Get the template data from DATA to access footers
const templateData = DATA[template.templateId || template.template_id];
Expand Down
Loading