// server/index.ts
import express2 from "express";

// server/routes.ts
import { createServer } from "http";

// server/storage.ts
var MemStorage = class {
  properties;
  contactSubmissions;
  testimonials;
  valuationRequests;
  propertyId;
  contactSubmissionId;
  testimonialId;
  valuationRequestId;
  constructor() {
    this.properties = /* @__PURE__ */ new Map();
    this.contactSubmissions = /* @__PURE__ */ new Map();
    this.testimonials = /* @__PURE__ */ new Map();
    this.valuationRequests = /* @__PURE__ */ new Map();
    this.propertyId = 1;
    this.contactSubmissionId = 1;
    this.testimonialId = 1;
    this.valuationRequestId = 1;
    this.initializeData();
  }
  initializeData() {
    const sampleTestimonials = [
      {
        name: "Michael & Sarah Thompson",
        location: "Bought in The Ridges",
        testimonial: "Dr. Duffy's expertise in The Ridges was invaluable. She knew every detail about the community and helped us find our dream home. Her negotiation skills saved us significantly on our purchase.",
        rating: 5,
        date: "March 2023"
      },
      {
        name: "Jennifer Ramirez",
        location: "Sold in Falcon Ridge",
        testimonial: "The marketing strategy Dr. Duffy implemented for our home was exceptional. Professional photography, targeted advertising, and her extensive network of high-net-worth clients led to a sale well above asking price.",
        rating: 5,
        date: "December 2022"
      },
      {
        name: "Robert & Elizabeth Chen",
        location: "Bought in Tournament Hills",
        testimonial: "As international buyers, we relied heavily on Dr. Duffy's knowledge and guidance. Her attention to detail and responsiveness made the entire process seamless despite being thousands of miles away for most of the transaction.",
        rating: 5,
        date: "August 2023"
      }
    ];
    const sampleProperties = [
      {
        title: "Elegant Desert Masterpiece",
        address: "24 Promontory Ridge Drive",
        city: "Las Vegas",
        state: "NV",
        zipCode: "89135",
        price: 425e4,
        bedrooms: 5,
        bathrooms: 6,
        squareFeet: 6300,
        description: "Stunning luxury home with panoramic views of the Las Vegas Strip and surrounding mountains. Custom finishes throughout with a resort-style backyard.",
        features: ["Pool", "Spa", "Outdoor Kitchen", "Home Theater", "Wine Cellar", "4 Car Garage"],
        propertyType: "Single Family",
        isFeatured: true,
        status: "For Sale",
        imageUrls: ["https://static01.nyt.com/images/2020/03/08/realestate/08veges1/08veges1-superJumbo.jpg"]
      },
      {
        title: "Modern Desert Retreat",
        address: "15 Painted Feather Way",
        city: "Las Vegas",
        state: "NV",
        zipCode: "89135",
        price: 585e4,
        bedrooms: 6,
        bathrooms: 8,
        squareFeet: 7500,
        description: "Contemporary architectural masterpiece with floor-to-ceiling windows showcasing breathtaking golf course and mountain views.",
        features: ["Infinity Pool", "Smart Home", "Glass Wine Cellar", "Home Gym", "Executive Office", "6 Car Garage"],
        propertyType: "Custom Home",
        isFeatured: true,
        status: "For Sale",
        imageUrls: ["https://theredhillgroup.files.wordpress.com/2011/05/ridges-golf.jpg"]
      },
      {
        title: "Spectacular Custom Estate",
        address: "9 Cloud Chaser Boulevard",
        city: "Las Vegas",
        state: "NV",
        zipCode: "89135",
        price: 7995e3,
        bedrooms: 7,
        bathrooms: 9,
        squareFeet: 10200,
        description: "One-of-a-kind luxury estate boasting unparalleled craftsmanship and premium amenities throughout. Located on an elevated lot with sweeping views.",
        features: ["Guest House", "Resort Pool", "Indoor Basketball Court", "Chef's Kitchen", "Elevator", "Home Theater"],
        propertyType: "Estate",
        isFeatured: true,
        status: "For Sale",
        imageUrls: ["https://static01.nyt.com/images/2020/03/08/realestate/08veges2/08veges2-superJumbo.jpg"]
      }
    ];
    sampleTestimonials.forEach((testimonial) => {
      this.createTestimonial(testimonial);
    });
    sampleProperties.forEach((property) => {
      this.createProperty(property);
    });
  }
  // Property methods
  async getProperties() {
    return Array.from(this.properties.values());
  }
  async getFeaturedProperties() {
    return Array.from(this.properties.values()).filter((property) => property.isFeatured);
  }
  async getPropertyById(id) {
    return this.properties.get(id);
  }
  async createProperty(property) {
    const id = this.propertyId++;
    const newProperty = { ...property, id };
    this.properties.set(id, newProperty);
    return newProperty;
  }
  // Contact submission methods
  async createContactSubmission(submission) {
    const id = this.contactSubmissionId++;
    const createdAt = /* @__PURE__ */ new Date();
    const newSubmission = {
      id,
      firstName: submission.firstName,
      lastName: submission.lastName,
      email: submission.email,
      phone: submission.phone,
      interest: submission.interest || null,
      message: submission.message || null,
      consent: submission.consent,
      createdAt
    };
    this.contactSubmissions.set(id, newSubmission);
    return newSubmission;
  }
  async getContactSubmissions() {
    return Array.from(this.contactSubmissions.values());
  }
  // Testimonial methods
  async getTestimonials() {
    return Array.from(this.testimonials.values());
  }
  async createTestimonial(testimonial) {
    const id = this.testimonialId++;
    const newTestimonial = { ...testimonial, id };
    this.testimonials.set(id, newTestimonial);
    return newTestimonial;
  }
  // Valuation request methods
  async createValuationRequest(request) {
    const id = this.valuationRequestId++;
    const createdAt = /* @__PURE__ */ new Date();
    const newRequest = {
      id,
      firstName: request.firstName,
      lastName: request.lastName,
      email: request.email,
      phone: request.phone,
      address: request.address,
      city: request.city,
      state: request.state,
      zipCode: request.zipCode,
      propertyType: request.propertyType || null,
      estimatedValue: request.estimatedValue || null,
      timeframe: request.timeframe || null,
      createdAt
    };
    this.valuationRequests.set(id, newRequest);
    return newRequest;
  }
  async getValuationRequests() {
    return Array.from(this.valuationRequests.values());
  }
  async getValuationRequestByEmail(email) {
    const requests = this.getValuationRequests();
    return (await requests).find((request) => request.email.toLowerCase() === email.toLowerCase());
  }
};
var storage = new MemStorage();

// shared/schema.ts
import { pgTable, text, serial, integer, boolean, timestamp } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
var users = pgTable("users", {
  id: serial("id").primaryKey(),
  username: text("username").notNull().unique(),
  password: text("password").notNull()
});
var insertUserSchema = createInsertSchema(users).pick({
  username: true,
  password: true
});
var contactRequests = pgTable("contact_requests", {
  id: serial("id").primaryKey(),
  firstName: text("first_name").notNull(),
  lastName: text("last_name").notNull(),
  email: text("email").notNull(),
  phone: text("phone").notNull(),
  interest: text("interest"),
  message: text("message"),
  consent: boolean("consent").notNull(),
  createdAt: timestamp("created_at").defaultNow()
});
var contactSchema = createInsertSchema(contactRequests).pick({
  firstName: true,
  lastName: true,
  email: true,
  phone: true,
  interest: true,
  message: true,
  consent: true
});
var propertyInquiries = pgTable("property_inquiries", {
  id: serial("id").primaryKey(),
  propertyId: text("property_id").notNull(),
  firstName: text("first_name").notNull(),
  lastName: text("last_name").notNull(),
  email: text("email").notNull(),
  phone: text("phone").notNull(),
  message: text("message"),
  createdAt: timestamp("created_at").defaultNow()
});
var propertyInquirySchema = createInsertSchema(propertyInquiries).pick({
  propertyId: true,
  firstName: true,
  lastName: true,
  email: true,
  phone: true,
  message: true
});
var valuationRequests = pgTable("valuation_requests", {
  id: serial("id").primaryKey(),
  firstName: text("first_name").notNull(),
  lastName: text("last_name").notNull(),
  email: text("email").notNull(),
  phone: text("phone").notNull(),
  address: text("address").notNull(),
  city: text("city").notNull(),
  state: text("state").notNull(),
  zipCode: text("zip_code").notNull(),
  propertyType: text("property_type"),
  estimatedValue: integer("estimated_value"),
  timeframe: text("timeframe"),
  createdAt: timestamp("created_at").defaultNow()
});
var valuationRequestSchema = createInsertSchema(valuationRequests).pick({
  firstName: true,
  lastName: true,
  email: true,
  phone: true,
  address: true,
  city: true,
  state: true,
  zipCode: true,
  propertyType: true,
  estimatedValue: true,
  timeframe: true
});

// server/services/followUpBoss.ts
import axios from "axios";
var FOLLOW_UP_BOSS_API_URL = "https://api.followupboss.com/v1";
var API_KEY = process.env.FOLLOW_UP_BOSS_API_KEY;
async function createContact(formData) {
  try {
    if (!API_KEY) {
      throw new Error("Follow Up Boss API Key is not set");
    }
    console.log(
      "Creating contact in Follow Up Boss with data:",
      JSON.stringify({
        firstName: formData.firstName,
        lastName: formData.lastName,
        email: formData.email,
        phone: formData.phone,
        interest: formData.interest,
        hasMessage: !!formData.message
      })
    );
    const personData = {
      firstName: formData.firstName,
      lastName: formData.lastName,
      emails: [{ value: formData.email, type: "primary" }],
      phones: [{ value: formData.phone, type: "mobile" }],
      source: "Website Contact Form",
      tags: formData.interest ? [formData.interest] : ["Website Inquiry"],
      // Use interest as a tag for segmentation
      notes: formData.message || (formData.interest ? `Interest: ${formData.interest}` : "Website inquiry")
    };
    const auth = {
      username: API_KEY,
      password: ""
    };
    console.log("Sending data to Follow Up Boss API...");
    const response = await axios.post(
      `${FOLLOW_UP_BOSS_API_URL}/people`,
      personData,
      { auth }
    );
    console.log(
      "Successfully created contact in Follow Up Boss:",
      JSON.stringify({
        id: response.data.id,
        status: response.status,
        statusText: response.statusText
      })
    );
    return response.data;
  } catch (error) {
    console.error("Error creating contact in Follow Up Boss:", error);
    throw error;
  }
}
async function checkExistingContact(email) {
  try {
    if (!API_KEY) {
      throw new Error("Follow Up Boss API Key is not set");
    }
    console.log(`Checking if contact exists in Follow Up Boss with email: ${email}`);
    const auth = {
      username: API_KEY,
      password: ""
    };
    const searchUrl = `${FOLLOW_UP_BOSS_API_URL}/people/search?email=${encodeURIComponent(email)}`;
    console.log(`Making request to: ${searchUrl}`);
    const response = await axios.get(searchUrl, { auth });
    console.log(
      "Follow Up Boss contact search response:",
      JSON.stringify({
        status: response.status,
        statusText: response.statusText,
        count: response.data?.people?.length || 0
      })
    );
    return response.data;
  } catch (error) {
    console.error("Error checking existing contact in Follow Up Boss:", error);
    throw error;
  }
}
var followUpBoss_default = {
  createContact,
  checkExistingContact
};

// server/routes.ts
import Parser from "rss-parser";
import axios2 from "axios";
async function registerRoutes(app2) {
  app2.post("/api/contact", async (req, res) => {
    try {
      const validatedData = contactSchema.parse(req.body);
      const contactRequest = await storage.createContactSubmission(validatedData);
      let followUpBossResponse = null;
      let followUpBossError = null;
      try {
        const existingContact = await followUpBoss_default.checkExistingContact(validatedData.email);
        if (!existingContact || existingContact.people.length === 0) {
          const contactData = {
            firstName: validatedData.firstName,
            lastName: validatedData.lastName,
            email: validatedData.email,
            phone: validatedData.phone,
            interest: validatedData.interest || null,
            message: validatedData.message || null,
            consent: validatedData.consent || false,
            consentGiven: validatedData.consent || false
            // Add this for compatibility with client type
          };
          followUpBossResponse = await followUpBoss_default.createContact(contactData);
          console.log("Contact created in Follow Up Boss:", followUpBossResponse);
        } else {
          console.log("Contact already exists in Follow Up Boss");
        }
      } catch (crmError) {
        console.error("Error with Follow Up Boss CRM:", crmError);
        followUpBossError = crmError instanceof Error ? crmError.message : "Unknown CRM error";
      }
      res.status(200).json({
        success: true,
        message: "Contact request received successfully",
        id: contactRequest.id,
        crmStatus: followUpBossError ? "error" : "success",
        crmMessage: followUpBossError || "Contact data sent to CRM"
      });
    } catch (error) {
      console.error("Error processing contact request:", error);
      res.status(400).json({
        success: false,
        message: "Invalid form data",
        error: error instanceof Error ? error.message : "Unknown error"
      });
    }
  });
  app2.post("/api/valuation", async (req, res) => {
    try {
      const validatedData = valuationRequestSchema.parse(req.body);
      const valuationRequest = await storage.createValuationRequest(validatedData);
      let followUpBossResponse = null;
      let followUpBossError = null;
      try {
        const existingContact = await followUpBoss_default.checkExistingContact(validatedData.email);
        if (!existingContact || existingContact.people.length === 0) {
          const contactData = {
            firstName: validatedData.firstName,
            lastName: validatedData.lastName,
            email: validatedData.email,
            phone: validatedData.phone,
            interest: "Home Valuation",
            // Tag this lead specifically for valuation
            message: `Property Address: ${validatedData.address}, ${validatedData.city}, ${validatedData.state} ${validatedData.zipCode}${validatedData.timeframe ? ` | Timeframe: ${validatedData.timeframe}` : ""}`,
            consentGiven: true
            // Assume consent was given if they submitted a valuation
          };
          followUpBossResponse = await followUpBoss_default.createContact(contactData);
          console.log("Valuation contact created in Follow Up Boss:", followUpBossResponse);
        } else {
          console.log("Contact already exists in Follow Up Boss");
        }
      } catch (crmError) {
        console.error("Error with Follow Up Boss CRM:", crmError);
        followUpBossError = crmError instanceof Error ? crmError.message : "Unknown CRM error";
      }
      res.status(200).json({
        success: true,
        message: "Valuation request received successfully",
        id: valuationRequest.id,
        crmStatus: followUpBossError ? "error" : "success",
        crmMessage: followUpBossError || "Valuation request sent to CRM"
      });
    } catch (error) {
      console.error("Error processing valuation request:", error);
      res.status(400).json({
        success: false,
        message: "Invalid valuation form data",
        error: error instanceof Error ? error.message : "Unknown error"
      });
    }
  });
  app2.get("/api/rss-feed", async (req, res) => {
    try {
      const { url } = req.query;
      if (!url || typeof url !== "string") {
        return res.status(400).json({
          success: false,
          message: "URL parameter is required"
        });
      }
      const parser = new Parser();
      const response = await axios2.get(url);
      const feed = await parser.parseString(response.data);
      res.status(200).json({
        success: true,
        title: feed.title,
        description: feed.description,
        link: feed.link,
        items: feed.items
      });
    } catch (error) {
      console.error("Error fetching RSS feed:", error);
      res.status(500).json({
        success: false,
        message: "Failed to fetch RSS feed",
        error: error instanceof Error ? error.message : "Unknown error"
      });
    }
  });
  const httpServer = createServer(app2);
  return httpServer;
}

// server/vite.ts
import express from "express";
import fs from "fs";
import path2 from "path";
import { createServer as createViteServer, createLogger } from "vite";

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import path from "path";
import runtimeErrorOverlay from "@replit/vite-plugin-runtime-error-modal";
var vite_config_default = defineConfig({
  plugins: [
    react(),
    runtimeErrorOverlay(),
    ...process.env.NODE_ENV !== "production" && process.env.REPL_ID !== void 0 ? [
      await import("@replit/vite-plugin-cartographer").then(
        (m) => m.cartographer()
      )
    ] : []
  ],
  resolve: {
    alias: {
      "@": path.resolve(import.meta.dirname, "client", "src"),
      "@shared": path.resolve(import.meta.dirname, "shared"),
      "@assets": path.resolve(import.meta.dirname, "attached_assets")
    }
  },
  root: path.resolve(import.meta.dirname, "client"),
  build: {
    outDir: path.resolve(import.meta.dirname, "dist/public"),
    emptyOutDir: true
  }
});

// server/vite.ts
import { nanoid } from "nanoid";
var viteLogger = createLogger();
function log(message, source = "express") {
  const formattedTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
    hour: "numeric",
    minute: "2-digit",
    second: "2-digit",
    hour12: true
  });
  console.log(`${formattedTime} [${source}] ${message}`);
}
async function setupVite(app2, server) {
  const serverOptions = {
    middlewareMode: true,
    hmr: { server },
    allowedHosts: true
  };
  const vite = await createViteServer({
    ...vite_config_default,
    configFile: false,
    customLogger: {
      ...viteLogger,
      error: (msg, options) => {
        viteLogger.error(msg, options);
        process.exit(1);
      }
    },
    server: serverOptions,
    appType: "custom"
  });
  app2.use(vite.middlewares);
  app2.use("*", async (req, res, next) => {
    const url = req.originalUrl;
    try {
      const clientTemplate = path2.resolve(
        import.meta.dirname,
        "..",
        "client",
        "index.html"
      );
      let template = await fs.promises.readFile(clientTemplate, "utf-8");
      template = template.replace(
        `src="/src/main.tsx"`,
        `src="/src/main.tsx?v=${nanoid()}"`
      );
      const page = await vite.transformIndexHtml(url, template);
      res.status(200).set({ "Content-Type": "text/html" }).end(page);
    } catch (e) {
      vite.ssrFixStacktrace(e);
      next(e);
    }
  });
}
function serveStatic(app2) {
  const distPath = path2.resolve(import.meta.dirname, "public");
  if (!fs.existsSync(distPath)) {
    throw new Error(
      `Could not find the build directory: ${distPath}, make sure to build the client first`
    );
  }
  app2.use(express.static(distPath));
  app2.use("*", (_req, res) => {
    res.sendFile(path2.resolve(distPath, "index.html"));
  });
}

// server/index.ts
var app = express2();
app.use(express2.json());
app.use(express2.urlencoded({ extended: false }));
app.use((req, res, next) => {
  const start = Date.now();
  const path3 = req.path;
  let capturedJsonResponse = void 0;
  const originalResJson = res.json;
  res.json = function(bodyJson, ...args) {
    capturedJsonResponse = bodyJson;
    return originalResJson.apply(res, [bodyJson, ...args]);
  };
  res.on("finish", () => {
    const duration = Date.now() - start;
    if (path3.startsWith("/api")) {
      let logLine = `${req.method} ${path3} ${res.statusCode} in ${duration}ms`;
      if (capturedJsonResponse) {
        logLine += ` :: ${JSON.stringify(capturedJsonResponse)}`;
      }
      if (logLine.length > 80) {
        logLine = logLine.slice(0, 79) + "\u2026";
      }
      log(logLine);
    }
  });
  next();
});
(async () => {
  const server = await registerRoutes(app);
  app.use((err, _req, res, _next) => {
    const status = err.status || err.statusCode || 500;
    const message = err.message || "Internal Server Error";
    res.status(status).json({ message });
    throw err;
  });
  if (app.get("env") === "development") {
    await setupVite(app, server);
  } else {
    serveStatic(app);
  }
  const port = 5e3;
  server.listen({
    port,
    host: "0.0.0.0",
    reusePort: true
  }, () => {
    const address = server.address();
    log(`serving on port ${port}`);
    if (address && typeof address !== "string") {
      log(`server available at http://${address.address}:${address.port}`);
    }
    log(`environment: ${app.get("env")}`);
  });
})();
