function Dashboard() { // State for profile data const [profile, setProfile] = React.useState({ firstName: "", lastName: "", level: "1", rank: "Beginner", points: "0 pts", initials: "", progress: 0, }); // State for stats cards const [stats, setStats] = React.useState({ activeListings: { count: "-", change: "--vs last month", percent: 0 }, promotionalListings: { count: "-", change: "--vs last month", percent: 0 }, publishedPosts: { count: "-", change: "--vs last month", percent: 0 }, scheduledPosts: { count: "-", change: "--vs last month", percent: 0 }, }); // State for news const [news, setNews] = React.useState({ loading: true, items: [] }); // Helper: get cookie by name function getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(";").shift(); return ""; } // Helper: calculate days ago function calculateDaysAgo(date) { if (!date || isNaN(date.getTime())) return "recently"; const now = new Date(); const diffTime = Math.abs(now - date); const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24)); if (diffDays === 0) return "today"; if (diffDays === 1) return "yesterday"; return diffDays + " days ago"; } // Fetch profile data React.useEffect(() => { const firstName = getCookie("app_u_first_name") || ""; const lastName = getCookie("app_u_last_name") || ""; const vendorToken = getCookie("app_u_token") || ""; const appName = getCookie("app_u_app_name") || ""; const apiKey = getCookie("get_local_vip_1580295343903_2_apikey") || ""; // Set initials const initials = (firstName.charAt(0).toUpperCase() || "") + (lastName.charAt(0).toUpperCase() || ""); // Fetch vendor points if (vendorToken && appName && apiKey) { const toSearch = { vendor_token: vendorToken }; const endpoint = `https://api.owlapplicationbuilder.com/api/entities/${appName}/vendor_points/get_all_en?to_search=${JSON.stringify( toSearch )}&page=1&page_size=10&srt=-1`; fetch(endpoint, { method: "GET", headers: { Accept: "*/*", "X-API-KEY": apiKey, }, }) .then((res) => res.json()) .then((responseData) => { if ( responseData && responseData.data && responseData.data.length > 0 ) { const vendorData = responseData.data[0]; let progressPercentage = 0; const score = vendorData.points || 0; const level = vendorData.level || 1; if (level === 1) progressPercentage = Math.min((score / 100) * 100, 100); else if (level === 2) progressPercentage = Math.min((score / 250) * 100, 100); else if (level === 3) progressPercentage = Math.min((score / 500) * 100, 100); else progressPercentage = Math.min((score / 1000) * 100, 100); setProfile({ firstName, lastName, initials, level: vendorData.level || "0", rank: vendorData.level ? vendorData.level.charAt(0).toUpperCase() + vendorData.level.slice(1) : "Beginner", points: (vendorData.points ?? "0") + " pts", progress: progressPercentage, }); } }); } else { setProfile((p) => ({ ...p, firstName, lastName, initials, })); } }, []); // Fetch news/announcements React.useEffect(() => { const appName = getCookie("app_u_app_name"); const apiKey = getCookie("get_local_vip_1580295343903_2_apikey") || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBfbmFtZSI6ImdldF9sb2NhbF92aXBfMTU4MDI5NTM0MzkwM18yIiwiaWF0IjoxNzIwNjA1NDkzfQ.bbmbXfYm3uNx_zVJn1w3TNBp7OJhDkWosa9Ik0Ofy8g"; const searchQuery = { status: "published" }; const queryParams = new URLSearchParams({ page: 1, page_size: 4, srt: -1, to_search: JSON.stringify(searchQuery), }); if (!appName) { setNews({ loading: false, items: [] }); return; } fetch( `https://api.owlapplicationbuilder.com/api/entities/${appName}/announcements/get_all_en?${queryParams.toString()}`, { method: "GET", headers: { Accept: "*/*", "X-API-KEY": apiKey, }, } ) .then((res) => res.json()) .then((responseData) => { if (responseData && Array.isArray(responseData.data)) { setNews({ loading: false, items: responseData.data }); } else { setNews({ loading: false, items: [] }); } }) .catch(() => setNews({ loading: false, items: [] })); }, []); // Fetch stats cards React.useEffect(() => { const app_name = getCookie("app_u_app_name"); const api_key = getCookie("get_local_vip_1580295343903_2_apikey"); const user_token = getCookie("app_u_token"); if (!app_name || !api_key || !user_token) return; // Helper for stats function updateStat(key, currentCount, referenceCount) { let percentChange = 0; let changeText = ""; if (referenceCount > 0 && referenceCount !== currentCount) { percentChange = ((currentCount - referenceCount) / referenceCount) * 100; const sign = percentChange >= 0 ? "+" : ""; changeText = `${sign}${percentChange.toFixed(1)}% vs last month`; } else if (currentCount > 0) { changeText = "+100% vs last month"; percentChange = 100; } else { changeText = "0% vs last month"; percentChange = 0; } setStats((s) => ({ ...s, [key]: { count: currentCount, change: changeText, percent: Math.max(Math.min(Math.abs(percentChange), 100), 0), }, })); } // Fetch offers function fetchOffers(searchable, key) { const searchParams = { $and: [ { utoken: user_token }, { status: "published" }, ...(searchable ? [{ searchable: "true" }] : []), ], }; const queryParams = new URLSearchParams({ search_columns: "token,title", to_search: JSON.stringify(searchParams), page: 1, page_size: 1000, srt: -1, }); const url = `https://api.owlapplicationbuilder.com/api/entities/${app_name}/offers/get_all_en?${queryParams.toString()}`; return fetch(url, { method: "GET", headers: { Accept: "*/*", "X-API-KEY": api_key, }, }) .then((res) => res.json()) .then((result) => result.data || []) .then((data) => { const currentCount = data.length; const referenceCount = Math.round(currentCount / 1.3); updateStat(key, currentCount, referenceCount); }) .catch(() => { setStats((s) => ({ ...s, [key]: { count: "Error", change: "Failed to load data", percent: 0 }, })); }); } // Fetch posts function fetchPosts(uploadStatus, key) { const searchParams = { $and: [{ user_token: user_token }, { upload: uploadStatus }], }; const queryParams = new URLSearchParams({ search_columns: "token,title", to_search: JSON.stringify(searchParams), page: 1, page_size: 1000, srt: -1, }); const url = `https://api.owlapplicationbuilder.com/api/entities/${app_name}/posts_queue/get_all_en?${queryParams.toString()}`; return fetch(url, { method: "GET", headers: { Accept: "*/*", "X-API-KEY": api_key, }, }) .then((res) => res.json()) .then((result) => result.data || []) .then((data) => { const currentCount = data.length; const referenceCount = key === "publishedPosts" ? Math.round(currentCount / 1.2) : Math.round(currentCount / 1.1); updateStat(key, currentCount, referenceCount); }) .catch(() => { setStats((s) => ({ ...s, [key]: { count: "Error", change: "Failed to load data", percent: 0 }, })); }); } fetchOffers(true, "activeListings"); fetchOffers(false, "promotionalListings"); fetchPosts("uploaded", "publishedPosts"); fetchPosts("scheduled", "scheduledPosts"); }, []); // Styles React.useEffect(() => { // Add font-awesome and bootstrap if not present const fa = document.querySelector('link[href*="font-awesome"]'); if (!fa) { const link = document.createElement("link"); link.rel = "stylesheet"; link.href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"; document.head.appendChild(link); } const bs = document.querySelector('link[href*="bootstrap"]'); if (!bs) { const link = document.createElement("link"); link.rel = "stylesheet"; link.href = "https://files.owlapplicationbuilder.com/assets/css/bootstrap_4.2.1.min.css"; document.head.appendChild(link); } }, []); return ( <>
Dashboard
Search
Welcome to GetLocal.VIP
Your journey to smarter business promotion starts here.
{profile.initials}
Hi, {profile.firstName} {profile.lastName}
View Profile Earn Points
Level: {profile.level}
Rank: {profile.rank}
Points: {profile.points}
Active 
Listings
{stats.activeListings.count}
{stats.activeListings.change}
Promotional 
Listings
{stats.promotionalListings.count}
{stats.promotionalListings.change}
Posts
Published
{stats.publishedPosts.count}
{stats.publishedPosts.change}
Posting in 
Queue
{stats.scheduledPosts.count}
{stats.scheduledPosts.change}
Recommended Actions

Create First Listing

Create an offer, coupon, event, or health care description

Create Listing 
5 min +50 pts

Manage Social Media

Manage your social accounts and postings.

Manage 
5 min +50 pts
PRO
icon-(9)

Video Content Creation

Showcase your video content to local audiences

Create Video 
5 min +50 pts
PRO

Post a Help Wanted Job

Find local talent for your growing business

PRO

Create and Promote Your Event

Drive attendance with targeted local marketing

PRO

Upgrade to PRO Plan

Unlock premium tools for maximum local impact

{/* News Section */}
News & Tips
View All
{news.loading ? (
Loading...
) : news.items.length > 0 ? ( news.items.map((announcement, idx) => { const title = announcement.title || "Untitled Announcement"; const createdDate = new Date( parseInt(announcement.created_at) || parseInt(announcement.createdAt) || Date.now() ); const daysAgo = calculateDaysAgo(createdDate); return (
{title}
Posted {daysAgo}
); }) ) : (

No News Available

)}
{/* End News Section */}
); } render( )