<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Gemini Data Dashboard</title>

    <!-- Tailwind CSS CDN -->

    <script src="https://cdn.tailwindcss.com"></script>

    <!-- Inter Font -->

    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">

    <style>

        body {

            font-family: 'Inter', sans-serif;

        }

        /* Custom styles for print, to ensure charts are visible */

        @media print {

            body {

                -webkit-print-color-adjust: exact !important;

                color-adjust: exact !important;

            }

            .no-print {

                display: none !important;

            }

        }

    </style>

</head>

<body class="bg-gray-100">

    <div id="root"></div>


    <!-- React CDN -->

    <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>

    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>

    <!-- Babel for JSX transformation -->

    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

    <!-- PapaParse CDN for CSV parsing -->

    <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script>

    <!-- Plotly.js CDN for charting -->

    <script src="https://cdn.plot.ly/plotly-2.30.0.min.js"></script>

    <!-- html2canvas for capturing HTML as image -->

    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>

    <!-- jsPDF for creating PDF from image -->

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>



    <script type="text/babel">

        // --- API Key Configuration ---

        // WARNING: For production, secure your API key using a backend or environment variables.

        // Embedding it directly in client-side code is for demonstration purposes only.

        const GEMINI_API_KEY = "AIzaSyC7SjhHIrA2VrmuYcTYFhCXR2Ffg09L2_Y";


        // Main App Component

        const App = () => {

            const [data, setData] = React.useState([]);

            const [filteredData, setFilteredData] = React.useState([]);

            const [isLoading, setIsLoading] = React.useState(false);

            const [error, setError] = React.useState(null);

            const [filters, setFilters] = React.useState({

                platform: 'All',

                sentiment: 'All',

                mediaType: 'All',

                location: 'All',

                startDate: '',

                endDate: '',

            });

            const [uniqueOptions, setUniqueOptions] = React.useState({

                platforms: [],

                sentiments: [],

                mediaTypes: [],

                locations: [],

            });


            // State for dynamic insights

            const [campaignSummaryText, setCampaignSummaryText] = React.useState("Unggah data untuk menghasilkan ringkasan strategi kampanye.");

            const [sentimentInsightsText, setSentimentInsightsText] = React.useState("Menunggu data dan AI untuk menghasilkan insight.");

            const [engagementInsightsText, setEngagementInsightsText] = React.useState("Menunggu data dan AI untuk menghasilkan insight.");

            const [platformInsightsText, setPlatformInsightsText] = React.useState("Menunggu data dan AI untuk menghasilkan insight.");

            const [mediaTypeInsightsText, setMediaTypeInsightsText] = React.useState("Menunggu data dan AI untuk menghasilkan insight.");

            const [locationInsightsText, setLocationInsightsText] = React.useState("Menunggu data dan AI untuk menghasilkan insight.");


            const groupName = "Kelompok Gemini Insight"; // Group Name


            // Refs for Plotly charts

            const sentimentPieRef = React.useRef(null);

            const engagementLineRef = React.useRef(null);

            const platformBarRef = React.useRef(null);

            const mediaPieRef = React.useRef(null);

            const locationBarRef = React.useRef(null);

            const dashboardRef = React.useRef(null); // Ref for the entire dashboard for PDF export


            // --- Gemini API Call Function ---

            const getGeminiResponse = async (prompt_text) => {

                if (!GEMINI_API_KEY) {

                    return "API Key tidak tersedia untuk menghasilkan insight.";

                }


                const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${GEMINI_API_KEY}`;

                const headers = {

                    'Content-Type': 'application/json'

                };

                const payload = {

                    contents: [{ role: "user", parts: [{ text: prompt_text }] }]

                };


                try {

                    const response = await fetch(apiUrl, {

                        method: 'POST',

                        headers: headers,

                        body: JSON.stringify(payload)

                    });


                    if (!response.ok) {

                        const errorData = await response.json();

                        throw new Error(`HTTP error! status: ${response.status}, message: ${JSON.stringify(errorData)}`);

                    }


                    const result = await response.json();


                    if (result.candidates && result.candidates.length > 0 &&

                        result.candidates[0].content && result.candidates[0].content.parts &&

                        result.candidates[0].content.parts.length > 0) {

                        return result.candidates[0].content.parts[0].text;

                    } else {

                        console.error("Unexpected API response structure:", result);

                        return "Tidak dapat menghasilkan insight. Struktur respons tidak terduga.";

                    }

                } catch (e) {

                    console.error("Error calling Gemini API:", e);

                    return `Terjadi kesalahan saat memanggil Gemini API: ${e.message}.`;

                }

            };


            // --- Data Cleaning Function ---

            const cleanData = (parsedData) => {

                const cleaned = parsedData.map(row => {

                    // Convert 'Date' to YYYY-MM-DD format for consistency and easier comparison

                    let cleanedDate = null;

                    if (row.Date) {

                        const dateObj = new Date(row.Date);

                        if (!isNaN(dateObj)) {

                            cleanedDate = dateObj.toISOString().split('T')[0]; // YYYY-MM-DD

                        }

                    }


                    // Fill empty 'Engagements' with 0 and convert to number

                    let engagements = parseFloat(row.Engagements);

                    if (isNaN(engagements)) {

                        engagements = 0;

                    }


                    return {

                        ...row,

                        Date: cleanedDate,

                        Engagements: engagements,

                    };

                });


                // Filter out rows where Date couldn't be parsed

                return cleaned.filter(row => row.Date !== null);

            };


            // --- CSV File Upload Handler ---

            const handleFileUpload = async (event) => {

                const file = event.target.files[0];

                if (file) {

                    setIsLoading(true);

                    setError(null);

                    setCampaignSummaryText("Menghasilkan ringkasan strategi kampanye..."); // Reset and show loading


                    window.Papa.parse(file, {

                        header: true,

                        skipEmptyLines: true,

                        complete: async (results) => {

                            if (results.errors.length) {

                                setError('Error parsing CSV: ' + results.errors[0].message);

                                setIsLoading(false);

                                return;

                            }

                            const cleaned = cleanData(results.data);

                            setData(cleaned);

                            setFilteredData(cleaned); // Initially, filtered data is all data


                            // Extract unique options for filters

                            const platforms = [...new Set(cleaned.map(d => d.Platform).filter(Boolean))].sort();

                            const sentiments = [...new Set(cleaned.map(d => d.Sentiment).filter(Boolean))].sort();

                            const mediaTypes = [...new Set(cleaned.map(d => d['Media Type']).filter(Boolean))].sort();

                            const locations = [...new Set(cleaned.map(d => d.Location).filter(Boolean))].sort();


                            setUniqueOptions({ platforms, sentiments, mediaTypes, locations });


                            // Generate initial campaign summary

                            if (cleaned.length > 0) {

                                const summaryPrompt = `

                                Berdasarkan data sosial media berikut (hanya 5 baris pertama untuk contoh):

                                ${JSON.stringify(cleaned.slice(0, 5), null, 2)}

                                dan kolom yang tersedia: ${Object.keys(cleaned[0] || {}).join(', ')}.

                                Tuliskan ringkasan strategi kampanye yang relevan dan singkat (sekitar 3-5 poin kunci) dalam bahasa Indonesia,

                                fokus pada engagement, sentimen, platform, media type, dan lokasi.

                                `;

                                const summary = await getGeminiResponse(summaryPrompt);

                                setCampaignSummaryText(summary);

                            } else {

                                setCampaignSummaryText("Tidak ada data yang diunggah untuk menghasilkan ringkasan strategi kampanye.");

                            }


                            setIsLoading(false);

                        },

                        error: (err) => {

                            setError('Failed to parse CSV: ' + err.message);

                            setIsLoading(false);

                        }

                    });

                }

            };


            // --- Apply Filters Logic ---

            const applyFilters = React.useCallback(() => {

                let currentFilteredData = [...data];


                if (filters.platform !== 'All') {

                    currentFilteredData = currentFilteredData.filter(d => d.Platform === filters.platform);

                }

                if (filters.sentiment !== 'All') {

                    currentFilteredData = currentFilteredData.filter(d => d.Sentiment === filters.sentiment);

                }

                if (filters.mediaType !== 'All') {

                    currentFilteredData = currentFilteredData.filter(d => d['Media Type'] === filters.mediaType);

                }

                if (filters.location !== 'All') {

                    currentFilteredData = currentFilteredData.filter(d => d.Location === filters.location);

                }


                // Date Range Filter

                if (filters.startDate && filters.endDate) {

                    const start = new Date(filters.startDate);

                    const end = new Date(filters.endDate);

                    currentFilteredData = currentFilteredData.filter(d => {

                        const date = new Date(d.Date);

                        return date >= start && date <= end;

                    });

                } else if (filters.startDate) {

                    const start = new Date(filters.startDate);

                    currentFilteredData = currentFilteredData.filter(d => {

                        const date = new Date(d.Date);

                        return date >= start;

                    });

                } else if (filters.endDate) {

                    const end = new Date(filters.endDate);

                    currentFilteredData = currentFilteredData.filter(d => {

                        const date = new Date(d.Date);

                        return date <= end;

                    });

                }


                setFilteredData(currentFilteredData);

            }, [data, filters]);


            React.useEffect(() => {

                applyFilters();

            }, [filters, data, applyFilters]); // Re-run when filters or original data changes


            // --- Chart Rendering Functions (using Plotly) & Insight Generation ---

            const renderSentimentPieChart = React.useCallback(async () => {

                if (!sentimentPieRef.current || !filteredData.length) {

                    setSentimentInsightsText("Menunggu data dan AI untuk menghasilkan insight.");

                    return;

                }


                const sentimentCounts = {};

                filteredData.forEach(d => {

                    const sentiment = d.Sentiment || 'Unknown';

                    sentimentCounts[sentiment] = (sentimentCounts[sentiment] || 0) + 1;

                });


                const plotData = [{

                    labels: Object.keys(sentimentCounts),

                    values: Object.values(sentimentCounts),

                    type: 'pie',

                    hole: .4,

                    textinfo: "label+percent",

                    marker: {

                        colors: ['#636EFA', '#EF553B', '#00CC96', '#AB63FA', '#FFA15A', '#19D3F3'],

                    },

                }];


                const layout = {

                    title: 'Sentiment Breakdown',

                    height: 400,

                    width: 500,

                    showlegend: true,

                    margin: { t: 50, b: 50, l: 50, r: 50 },

                    font: { family: 'Inter, sans-serif' },

                };

                window.Plotly.newPlot(sentimentPieRef.current, plotData, layout, {responsive: true});


                // Generate dynamic insight

                setSentimentInsightsText("Menghasilkan insight sentimen...");

                const insightPrompt = `

                Berdasarkan data sentimen berikut (sentimen: jumlah): ${JSON.stringify(sentimentCounts)}.

                Berikan 3 insight singkat dan relevan tentang sentimen ini dalam bahasa Indonesia.

                `;

                const insights = await getGeminiResponse(insightPrompt);

                setSentimentInsightsText(insights);

            }, [filteredData]);


            const renderEngagementLineChart = React.useCallback(async () => {

                if (!engagementLineRef.current || !filteredData.length) {

                    setEngagementInsightsText("Menunggu data dan AI untuk menghasilkan insight.");

                    return;

                }


                const engagementByDate = {};

                filteredData.forEach(d => {

                    if (d.Date) {

                        engagementByDate[d.Date] = (engagementByDate[d.Date] || 0) + d.Engagements;

                    }

                });


                const sortedDates = Object.keys(engagementByDate).sort();

                const engagements = sortedDates.map(date => engagementByDate[date]);


                const plotData = [{

                    x: sortedDates,

                    y: engagements,

                    mode: 'lines+markers',

                    name: 'Engagements',

                    line: { color: '#EF553B' },

                }];


                const layout = {

                    title: 'Engagement Trend over Time',

                    xaxis: { title: 'Date', type: 'date', tickformat: '%Y-%m-%d' },

                    yaxis: { title: 'Total Engagements' },

                    height: 400,

                    width: 700,

                    margin: { t: 50, b: 70, l: 70, r: 50 },

                    font: { family: 'Inter, sans-serif' },

                };

                window.Plotly.newPlot(engagementLineRef.current, plotData, layout, {responsive: true});


                // Generate dynamic insight

                setEngagementInsightsText("Menghasilkan insight tren engagement...");

                const insightPrompt = `

                Berdasarkan tren engagement berikut (tanggal: engagement): ${JSON.stringify(engagementByDate)}.

                Berikan 3 insight singkat dan relevan tentang tren engagement ini dalam bahasa Indonesia.

                `;

                const insights = await getGeminiResponse(insightPrompt);

                setEngagementInsightsText(insights);

            }, [filteredData]);


            const renderPlatformBarChart = React.useCallback(async () => {

                if (!platformBarRef.current || !filteredData.length) {

                    setPlatformInsightsText("Menunggu data dan AI untuk menghasilkan insight.");

                    return;

                }


                const platformEngagements = {};

                filteredData.forEach(d => {

                    const platform = d.Platform || 'Unknown';

                    platformEngagements[platform] = (platformEngagements[platform] || 0) + d.Engagements;

                });


                const platforms = Object.keys(platformEngagements);

                const engagements = Object.values(platformEngagements);


                const plotData = [{

                    x: platforms,

                    y: engagements,

                    type: 'bar',

                    marker: { color: '#00CC96' },

                }];


                const layout = {

                    title: 'Platform Engagements',

                    xaxis: { title: 'Platform' },

                    yaxis: { title: 'Total Engagements' },

                    height: 400,

                    width: 700,

                    margin: { t: 50, b: 70, l: 70, r: 50 },

                    font: { family: 'Inter, sans-serif' },

                };

                window.Plotly.newPlot(platformBarRef.current, plotData, layout, {responsive: true});


                // Generate dynamic insight

                setPlatformInsightsText("Menghasilkan insight platform engagement...");

                const insightPrompt = `

                Berdasarkan engagement platform berikut (platform: engagement): ${JSON.stringify(platformEngagements)}.

                Berikan 3 insight singkat dan relevan tentang engagement platform ini dalam bahasa Indonesia.

                `;

                const insights = await getGeminiResponse(insightPrompt);

                setPlatformInsightsText(insights);

            }, [filteredData]);


            const renderMediaTypePieChart = React.useCallback(async () => {

                if (!mediaPieRef.current || !filteredData.length) {

                    setMediaTypeInsightsText("Menunggu data dan AI untuk menghasilkan insight.");

                    return;

                }


                const mediaTypeCounts = {};

                filteredData.forEach(d => {

                    const mediaType = d['Media Type'] || 'Unknown';

                    mediaTypeCounts[mediaType] = (mediaTypeCounts[mediaType] || 0) + 1;

                });


                const plotData = [{

                    labels: Object.keys(mediaTypeCounts),

                    values: Object.values(mediaTypeCounts),

                    type: 'pie',

                    hole: .4,

                    textinfo: "label+percent",

                    marker: {

                        colors: ['#AB63FA', '#FFA15A', '#19D3F3', '#636EFA', '#EF553B', '#00CC96'],

                    },

                }];


                const layout = {

                    title: 'Media Type Mix',

                    height: 400,

                    width: 500,

                    showlegend: true,

                    margin: { t: 50, b: 50, l: 50, r: 50 },

                    font: { family: 'Inter, sans-serif' },

                };

                window.Plotly.newPlot(mediaPieRef.current, plotData, layout, {responsive: true});


                // Generate dynamic insight

                setMediaTypeInsightsText("Menghasilkan insight jenis media...");

                const insightPrompt = `

                Berdasarkan jenis media berikut (jenis media: jumlah): ${JSON.stringify(mediaTypeCounts)}.

                Berikan 3 insight singkat dan relevan tentang jenis media ini dalam bahasa Indonesia.

                `;

                const insights = await getGeminiResponse(insightPrompt);

                setMediaTypeInsightsText(insights);

            }, [filteredData]);


            const renderLocationBarChart = React.useCallback(async () => {

                if (!locationBarRef.current || !filteredData.length) {

                    setLocationInsightsText("Menunggu data dan AI untuk menghasilkan insight.");

                    return;

                }


                const locationCounts = {};

                filteredData.forEach(d => {

                    const location = d.Location || 'Unknown';

                    locationCounts[location] = (locationCounts[location] || 0) + 1;

                });


                // Sort locations by count and take top 5

                const sortedLocations = Object.entries(locationCounts)

                    .sort(([, countA], [, countB]) => countB - countA)

                    .slice(0, 5);


                const locations = sortedLocations.map(([loc]) => loc);

                const counts = sortedLocations.map(([, count]) => count);


                const plotData = [{

                    x: locations,

                    y: counts,

                    type: 'bar',

                    marker: { color: '#AB63FA' },

                }];


                const layout = {

                    title: 'Top 5 Locations',

                    xaxis: { title: 'Location' },

                    yaxis: { title: 'Number of Posts' },

                    height: 400,

                    width: 700,

                    margin: { t: 50, b: 70, l: 70, r: 50 },

                    font: { family: 'Inter, sans-serif' },

                };

                window.Plotly.newPlot(locationBarRef.current, plotData, layout, {responsive: true});


                // Generate dynamic insight

                setLocationInsightsText("Menghasilkan insight lokasi...");

                const insightPrompt = `

                Berdasarkan 5 lokasi teratas berikut (lokasi: jumlah): ${JSON.stringify(Object.fromEntries(sortedLocations))}.

                Berikan 3 insight singkat dan relevan tentang lokasi ini dalam bahasa Indonesia.

                `;

                const insights = await getGeminiResponse(insightPrompt);

                setLocationInsightsText(insights);

            }, [filteredData]);


            // --- Render charts whenever filteredData changes ---

            React.useEffect(() => {

                if (filteredData.length) {

                    renderSentimentPieChart();

                    renderEngagementLineChart();

                    renderPlatformBarChart();

                    renderMediaTypePieChart();

                    renderLocationBarChart();

                } else {

                    // Clear charts if no data

                    if (window.Plotly) {

                        if (sentimentPieRef.current) window.Plotly.purge(sentimentPieRef.current);

                        if (engagementLineRef.current) window.Plotly.purge(engagementLineRef.current);

                        if (platformBarRef.current) window.Plotly.purge(platformBarRef.current);

                        if (mediaPieRef.current) window.Plotly.purge(mediaPieRef.current);

                        if (locationBarRef.current) window.Plotly.purge(locationBarRef.current);

                    }

                    // Reset insights when data is cleared

                    setSentimentInsightsText("Menunggu data dan AI untuk menghasilkan insight.");

                    setEngagementInsightsText("Menunggu data dan AI untuk menghasilkan insight.");

                    setPlatformInsightsText("Menunggu data dan AI untuk menghasilkan insight.");

                    setMediaTypeInsightsText("Menunggu data dan AI untuk menghasilkan insight.");

                    setLocationInsightsText("Menunggu data dan AI untuk menghasilkan insight.");

                }

            }, [filteredData, renderSentimentPieChart, renderEngagementLineChart, renderPlatformBarChart, renderMediaTypePieChart, renderLocationBarChart]);


            // --- Export to PDF Function ---

            const exportDashboardToPdf = () => {

                setIsLoading(true);

                setError(null);

                // Temporarily hide elements that shouldn't be in the PDF

                const elementsToHide = document.querySelectorAll('.no-print');

                elementsToHide.forEach(el => el.style.display = 'none');


                html2canvas(dashboardRef.current, {

                    scale: 2, // Increase scale for better resolution

                    useCORS: true, // Needed if your assets are from different origin (e.g., fonts)

                }).then(canvas => {

                    const imgData = canvas.toDataURL('image/png');

                    const pdf = new window.jspdf.jsPDF('p', 'mm', 'a4'); // 'p' for portrait, 'mm' for units, 'a4' for size

                    const imgWidth = 210; // A4 width in mm

                    const pageHeight = 297; // A4 height in mm

                    const imgHeight = canvas.height * imgWidth / canvas.width;

                    let heightLeft = imgHeight;

                    let position = 0;


                    pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);

                    heightLeft -= pageHeight;


                    while (heightLeft >= 0) {

                        position = heightLeft - imgHeight;

                        pdf.addPage();

                        pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);

                        heightLeft -= pageHeight;

                    }


                    pdf.save('gemini-dashboard.pdf');

                    setIsLoading(false);


                    // Show hidden elements again

                    elementsToHide.forEach(el => el.style.display = '');

                }).catch(err => {

                    setError('Failed to export PDF: ' + err.message);

                    setIsLoading(false);

                    // Ensure elements are shown even on error

                    elementsToHide.forEach(el => el.style.display = '');

                });

            };


            return (

                <div ref={dashboardRef} className="min-h-screen bg-gray-100 p-4 font-sans text-gray-800">

                    <div className="max-w-7xl mx-auto bg-white shadow-lg rounded-xl p-8 mb-8">

                        <h1 className="text-4xl font-bold text-center text-indigo-700 mb-6">Gemini Data Dashboard</h1>

                        <p className="text-center text-lg text-gray-600 mb-8">

                            Analisis data media sosial Anda dengan visualisasi interaktif.

                        </p>


                        {/* Group Name */}

                        <div className="text-center text-indigo-600 text-xl font-semibold mb-8 border-t border-b border-indigo-200 py-3">

                            {groupName}

                        </div>


                        {/* File Upload Section */}

                        <div className="mb-8 p-6 bg-indigo-50 rounded-lg shadow-sm no-print">

                            <label htmlFor="csv-upload" className="block text-xl font-medium text-indigo-800 mb-3">

                                Unggah File CSV:

                            </label>

                            <input

                                id="csv-upload"

                                type="file"

                                accept=".csv"

                                onChange={handleFileUpload}

                                className="block w-full text-sm text-gray-700

                                    file:mr-4 file:py-2 file:px-4

                                    file:rounded-full file:border-0

                                    file:text-sm file:font-semibold

                                    file:bg-indigo-500 file:text-white

                                    hover:file:bg-indigo-600 cursor-pointer"

                            />

                            {isLoading && <p className="mt-3 text-indigo-600">Memuat dan membersihkan data...</p>}

                            {error && <p className="mt-3 text-red-600">Error: {error}</p>}

                            {!data.length && !isLoading && (

                                <p className="mt-3 text-gray-500 text-sm">

                                    Harap unggah file CSV dengan kolom seperti: 'Date', 'Engagements', 'Platform', 'Sentiment', 'Media Type', 'Location'.

                                </p>

                            )}

                        </div>


                        {data.length > 0 && (

                            <>

                                {/* Export PDF Button */}

                                <div className="text-center mb-8 no-print">

                                    <button

                                        onClick={exportDashboardToPdf}

                                        className="px-8 py-3 bg-green-600 text-white font-semibold rounded-lg shadow-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-opacity-75 transition duration-150 ease-in-out"

                                        disabled={isLoading}

                                    >

                                        {isLoading ? 'Mengekspor...' : 'Ekspor Dashboard ke PDF'}

                                    </button>

                                </div>


                                {/* Key Action Summary Section (Dynamic) */}

                                <div className="mb-10 p-6 bg-blue-50 rounded-lg shadow-sm">

                                    <h2 className="text-2xl font-semibold text-blue-800 mb-4">Ringkasan Strategi Kampanye (Key Action Summary)</h2>

                                    <div className="text-gray-700 leading-relaxed">

                                        <p>{campaignSummaryText}</p>

                                    </div>

                                </div>


                                {/* Filters Section */}

                                <div className="mb-10 p-6 bg-purple-50 rounded-lg shadow-sm no-print">

                                    <h2 className="text-2xl font-semibold text-purple-800 mb-4">Saring Data</h2>

                                    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">

                                        {/* Platform Filter */}

                                        <div>

                                            <label htmlFor="platform-filter" className="block text-sm font-medium text-gray-700 mb-1">Platform:</label>

                                            <select

                                                id="platform-filter"

                                                value={filters.platform}

                                                onChange={(e) => setFilters({ ...filters, platform: e.target.value })}

                                                className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm rounded-md shadow-sm"

                                            >

                                                <option value="All">Semua Platform</option>

                                                {uniqueOptions.platforms.map(option => (

                                                    <option key={option} value={option}>{option}</option>

                                                ))}

                                            </select>

                                        </div>


                                        {/* Sentiment Filter */}

                                        <div>

                                            <label htmlFor="sentiment-filter" className="block text-sm font-medium text-gray-700 mb-1">Sentimen:</label>

                                            <select

                                                id="sentiment-filter"

                                                value={filters.sentiment}

                                                onChange={(e) => setFilters({ ...filters, sentiment: e.target.value })}

                                                className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm rounded-md shadow-sm"

                                            >

                                                <option value="All">Semua Sentimen</option>

                                                {uniqueOptions.sentiments.map(option => (

                                                    <option key={option} value={option}>{option}</option>

                                                ))}

                                            </select>

                                        </div>


                                        {/* Media Type Filter */}

                                        <div>

                                            <label htmlFor="media-type-filter" className="block text-sm font-medium text-gray-700 mb-1">Jenis Media:</label>

                                            <select

                                                id="media-type-filter"

                                                value={filters.mediaType}

                                                onChange={(e) => setFilters({ ...filters, mediaType: e.target.value })}

                                                className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm rounded-md shadow-sm"

                                            >

                                                <option value="All">Semua Jenis Media</option>

                                                {uniqueOptions.mediaTypes.map(option => (

                                                    <option key={option} value={option}>{option}</option>

                                                ))}

                                            </select>

                                        </div>


                                        {/* Location Filter */}

                                        <div>

                                            <label htmlFor="location-filter" className="block text-sm font-medium text-gray-700 mb-1">Lokasi:</label>

                                            <select

                                                id="location-filter"

                                                value={filters.location}

                                                onChange={(e) => setFilters({ ...filters, location: e.target.value })}

                                                className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm rounded-md shadow-sm"

                                            >

                                                <option value="All">Semua Lokasi</option>

                                                {uniqueOptions.locations.map(option => (

                                                    <option key={option} value={option}>{option}</option>

                                                ))}

                                            </select>

                                        </div>


                                        {/* Start Date Filter */}

                                        <div>

                                            <label htmlFor="start-date-filter" className="block text-sm font-medium text-gray-700 mb-1">Tanggal Mulai:</label>

                                            <input

                                                id="start-date-filter"

                                                type="date"

                                                value={filters.startDate}

                                                onChange={(e) => setFilters({ ...filters, startDate: e.target.value })}

                                                className="mt-1 block w-full pl-3 pr-3 py-2 text-base border-gray-300 focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm rounded-md shadow-sm"

                                            />

                                        </div>


                                        {/* End Date Filter */}

                                        <div>

                                            <label htmlFor="end-date-filter" className="block text-sm font-medium text-gray-700 mb-1">Tanggal Berakhir:</label>

                                            <input

                                                id="end-date-filter"

                                                type="date"

                                                value={filters.endDate}

                                                onChange={(e) => setFilters({ ...filters, endDate: e.target.value })}

                                                className="mt-1 block w-full pl-3 pr-3 py-2 text-base border-gray-300 focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm rounded-md shadow-sm"

                                            />

                                        </div>

                                    </div>

                                    <div className="mt-6 text-center">

                                        <button

                                            onClick={() => setFilters({

                                                platform: 'All',

                                                sentiment: 'All',

                                                mediaType: 'All',

                                                location: 'All',

                                                startDate: '',

                                                endDate: '',

                                            })}

                                            className="px-6 py-2 bg-gray-200 text-gray-800 rounded-lg shadow-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-opacity-75 transition duration-150 ease-in-out"

                                        >

                                            Atur Ulang Filter

                                        </button>

                                    </div>

                                </div>


                                {/* Visualizations Section */}

                                <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">

                                    {/* Sentiment Breakdown */}

                                    <div className="bg-white p-6 rounded-xl shadow-md flex flex-col items-center">

                                        <div ref={sentimentPieRef} className="w-full h-full min-h-[400px]"></div>

                                        <h3 className="text-xl font-semibold text-gray-700 mt-4 mb-2">Insight:</h3>

                                        <div className="text-gray-600 text-sm insights-list">

                                            <p>{sentimentInsightsText}</p>

                                        </div>

                                    </div>


                                    {/* Engagement Trend */}

                                    <div className="bg-white p-6 rounded-xl shadow-md flex flex-col items-center">

                                        <div ref={engagementLineRef} className="w-full h-full min-h-[400px]"></div>

                                        <h3 className="text-xl font-semibold text-gray-700 mt-4 mb-2">Insight:</h3>

                                        <div className="text-gray-600 text-sm insights-list">

                                            <p>{engagementInsightsText}</p>

                                        </div>

                                    </div>


                                    {/* Platform Engagements */}

                                    <div className="bg-white p-6 rounded-xl shadow-md flex flex-col items-center">

                                        <div ref={platformBarRef} className="w-full h-full min-h-[400px]"></div>

                                        <h3 className="text-xl font-semibold text-gray-700 mt-4 mb-2">Insight:</h3>

                                        <div className="text-gray-600 text-sm insights-list">

                                            <p>{platformInsightsText}</p>

                                        </div>

                                    </div>


                                    {/* Media Type Mix */}

                                    <div className="bg-white p-6 rounded-xl shadow-md flex flex-col items-center">

                                        <div ref={mediaPieRef} className="w-full h-full min-h-[400px]"></div>

                                        <h3 className="text-xl font-semibold text-gray-700 mt-4 mb-2">Insight:</h3>

                                        <div className="text-gray-600 text-sm insights-list">

                                            <p>{mediaTypeInsightsText}</p>

                                        </div>

                                    </div>


                                    {/* Top 5 Locations */}

                                    <div className="bg-white p-6 rounded-xl shadow-md col-span-1 lg:col-span-2 flex flex-col items-center">

                                        <div ref={locationBarRef} className="w-full h-full min-h-[400px]"></div>

                                        <h3 className="text-xl font-semibold text-gray-700 mt-4 mb-2">Insight:</h3>

                                        <div className="text-gray-600 text-sm insights-list">

                                            <p>{locationInsightsText}</p>

                                        </div>

                                    </div>

                                </div>

                            </>

                        )}

                    </div>

                </div>

            );

        };


        // Render the React component into the 'root' div

        ReactDOM.createRoot(document.getElementById('root')).render(<App />);

    </script>

</body>

</html>