mirror of
https://github.com/FranP-code/inbox-negotiator.git
synced 2025-10-13 00:42:26 +00:00
Implement debt variable management with database integration in DebtCard component
This commit is contained in:
@@ -27,8 +27,8 @@ import {
|
||||
TrendingUp,
|
||||
Edit3,
|
||||
} from "lucide-react";
|
||||
import { supabase } from "../lib/supabase";
|
||||
import type { Debt } from "../lib/supabase";
|
||||
import { supabase, type Debt, type DebtVariable } from "../lib/supabase";
|
||||
import { toast } from "../hooks/use-toast";
|
||||
|
||||
interface DebtCardProps {
|
||||
debt: Debt;
|
||||
@@ -110,22 +110,82 @@ export function DebtCard({ debt, onUpdate }: DebtCardProps) {
|
||||
const [body, setBody] = useState("");
|
||||
const [variables, setVariables] = useState<Record<string, string>>({});
|
||||
|
||||
// Load variables from database
|
||||
const loadVariables = async () => {
|
||||
try {
|
||||
const { data: dbVariables, error } = await supabase
|
||||
.from("debt_variables")
|
||||
.select("variable_name, variable_value")
|
||||
.eq("debt_id", debt.id);
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
const loadedVariables: Record<string, string> = {};
|
||||
dbVariables?.forEach((dbVar) => {
|
||||
loadedVariables[dbVar.variable_name] = dbVar.variable_value || "";
|
||||
});
|
||||
|
||||
return loadedVariables;
|
||||
} catch (error) {
|
||||
console.error("Error loading variables:", error);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
// Save variables to database
|
||||
const saveVariables = async (variablesToSave: Record<string, string>) => {
|
||||
try {
|
||||
// First, delete existing variables for this debt
|
||||
await supabase.from("debt_variables").delete().eq("debt_id", debt.id);
|
||||
|
||||
// Then insert new variables
|
||||
const variableRecords = Object.entries(variablesToSave).map(
|
||||
([name, value]) => ({
|
||||
debt_id: debt.id,
|
||||
variable_name: name,
|
||||
variable_value: value,
|
||||
})
|
||||
);
|
||||
|
||||
if (variableRecords.length > 0) {
|
||||
const { error } = await supabase
|
||||
.from("debt_variables")
|
||||
.insert(variableRecords);
|
||||
|
||||
if (error) throw error;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error saving variables:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize data when dialog opens
|
||||
useEffect(() => {
|
||||
if (debt.metadata?.aiEmail) {
|
||||
const aiEmail = debt.metadata.aiEmail;
|
||||
setSubject(aiEmail.subject || "");
|
||||
setBody(aiEmail.body || "");
|
||||
const initializeData = async () => {
|
||||
if (debt.metadata?.aiEmail) {
|
||||
const aiEmail = debt.metadata.aiEmail;
|
||||
setSubject(aiEmail.subject || "");
|
||||
setBody(aiEmail.body || "");
|
||||
|
||||
// Extract variables from both subject and body
|
||||
const allText = `${aiEmail.subject || ""} ${aiEmail.body || ""}`;
|
||||
const extractedVars = extractVariables(allText);
|
||||
const initialVariables: Record<string, string> = {};
|
||||
extractedVars.forEach((variable) => {
|
||||
initialVariables[variable] = "";
|
||||
});
|
||||
setVariables(initialVariables);
|
||||
}
|
||||
// Extract variables from both subject and body
|
||||
const allText = `${aiEmail.subject || ""} ${aiEmail.body || ""}`;
|
||||
const extractedVars = extractVariables(allText);
|
||||
|
||||
// Load saved variables from database
|
||||
const savedVariables = await loadVariables();
|
||||
|
||||
// Merge extracted variables with saved values
|
||||
const initialVariables: Record<string, string> = {};
|
||||
extractedVars.forEach((variable) => {
|
||||
initialVariables[variable] = savedVariables[variable] || "";
|
||||
});
|
||||
|
||||
setVariables(initialVariables);
|
||||
}
|
||||
};
|
||||
|
||||
initializeData();
|
||||
}, [debt.metadata?.aiEmail]);
|
||||
|
||||
// Update variables when body changes
|
||||
@@ -223,11 +283,24 @@ export function DebtCard({ debt, onUpdate }: DebtCardProps) {
|
||||
.eq("id", debt.id);
|
||||
|
||||
if (error) {
|
||||
console.error("Error saving changes:", error);
|
||||
// You could add toast notification here
|
||||
console.error("Error saving debt metadata:", error);
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Failed to save email changes. Please try again.",
|
||||
variant: "destructive",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Save variables to database
|
||||
await saveVariables(variables);
|
||||
|
||||
toast({
|
||||
title: "Changes saved",
|
||||
description:
|
||||
"Your email and variables have been updated successfully.",
|
||||
});
|
||||
|
||||
// Call onUpdate callback to refresh the parent component
|
||||
if (onUpdate) {
|
||||
onUpdate();
|
||||
@@ -236,6 +309,11 @@ export function DebtCard({ debt, onUpdate }: DebtCardProps) {
|
||||
setIsEditing(false);
|
||||
} catch (error) {
|
||||
console.error("Error saving changes:", error);
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Failed to save changes. Please try again.",
|
||||
variant: "destructive",
|
||||
});
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
const supabaseUrl = import.meta.env.PUBLIC_SUPABASE_URL;
|
||||
const supabaseAnonKey = import.meta.env.PUBLIC_SUPABASE_ANON_KEY;
|
||||
|
||||
if (!supabaseUrl || !supabaseAnonKey) {
|
||||
throw new Error('Missing Supabase environment variables');
|
||||
throw new Error("Missing Supabase environment variables");
|
||||
}
|
||||
|
||||
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
|
||||
@@ -22,7 +22,7 @@ export type Debt = {
|
||||
vendor: string;
|
||||
amount: number;
|
||||
raw_email: string | null;
|
||||
status: 'received' | 'negotiating' | 'settled' | 'failed' | 'opted_out';
|
||||
status: "received" | "negotiating" | "settled" | "failed" | "opted_out";
|
||||
negotiated_plan: string | null;
|
||||
projected_savings: number;
|
||||
user_id: string;
|
||||
@@ -66,4 +66,13 @@ export type EmailProcessingUsage = {
|
||||
emails_processed: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type DebtVariable = {
|
||||
id: string;
|
||||
debt_id: string;
|
||||
variable_name: string;
|
||||
variable_value: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
53
supabase/migrations/20250607008000_add_debt_variables.sql
Normal file
53
supabase/migrations/20250607008000_add_debt_variables.sql
Normal file
@@ -0,0 +1,53 @@
|
||||
-- Create debt_variables table to store variable values for each debt
|
||||
CREATE TABLE IF NOT EXISTS debt_variables (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
debt_id uuid REFERENCES debts(id) ON DELETE CASCADE NOT NULL,
|
||||
variable_name text NOT NULL,
|
||||
variable_value text,
|
||||
created_at timestamptz DEFAULT now(),
|
||||
updated_at timestamptz DEFAULT now(),
|
||||
UNIQUE(debt_id, variable_name)
|
||||
);
|
||||
|
||||
-- Enable RLS
|
||||
ALTER TABLE debt_variables ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Create policies for debt_variables
|
||||
CREATE POLICY "Users can manage their debt variables"
|
||||
ON debt_variables
|
||||
FOR ALL
|
||||
TO authenticated
|
||||
USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM debts
|
||||
WHERE debts.id = debt_variables.debt_id
|
||||
AND debts.user_id = auth.uid()
|
||||
)
|
||||
)
|
||||
WITH CHECK (
|
||||
EXISTS (
|
||||
SELECT 1 FROM debts
|
||||
WHERE debts.id = debt_variables.debt_id
|
||||
AND debts.user_id = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Create indexes for performance
|
||||
CREATE INDEX IF NOT EXISTS idx_debt_variables_debt_id ON debt_variables(debt_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_debt_variables_name ON debt_variables(variable_name);
|
||||
|
||||
-- Create function to update updated_at timestamp
|
||||
CREATE OR REPLACE FUNCTION update_debt_variables_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = now();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
-- Create trigger for updated_at
|
||||
DROP TRIGGER IF EXISTS update_debt_variables_updated_at ON debt_variables;
|
||||
CREATE TRIGGER update_debt_variables_updated_at
|
||||
BEFORE UPDATE ON debt_variables
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_debt_variables_updated_at_column();
|
||||
Reference in New Issue
Block a user