File size: 6,020 Bytes
d547a7b
7c2bec2
0be9c61
 
abcf498
0be9c61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31300e6
 
 
 
 
abcf498
31300e6
 
 
 
 
 
d547a7b
 
 
 
 
 
 
 
 
 
 
 
 
abcf498
d547a7b
31300e6
 
 
b366eeb
7c2bec2
31300e6
b366eeb
d547a7b
7c2bec2
31300e6
7c2bec2
 
d547a7b
b366eeb
31300e6
 
 
 
 
d547a7b
31300e6
 
 
 
 
d547a7b
31300e6
 
 
 
 
 
 
 
d547a7b
31300e6
 
d547a7b
 
 
 
 
 
 
 
 
 
 
31300e6
 
 
 
 
 
b366eeb
abcf498
 
31300e6
e06118d
31300e6
d547a7b
 
 
 
 
 
 
 
 
 
31300e6
 
 
 
 
abcf498
e06118d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// scripts/ui.js -- Final version with dropdown form and instant UI update

// --- THIS IS THE CRUCIAL UPDATE ---
const BACKEND_URL = 'https://streamai-backend-v2.smplushypermedia.workers.dev';

async function loadRecommendations() {
    const container = document.getElementById('recommendations-container');
    if (!container) return;

    try {
        // This now calls the NEW worker's recommendations endpoint
        const response = await fetch(`${BACKEND_URL}/api/recommendations`);
        
        if (!response.ok) {
            throw new Error(`Network response was not ok. Status: ${response.status}`);
        }

        const listings = await response.json();
        // ... (The rest of the rendering logic remains the same) ...
        container.innerHTML = '';
        listings.forEach(item => {
            const card = document.createElement('div');
            // ...card creation logic...
            container.appendChild(card);
        });

    } catch (error) {
        console.error("Failed to load recommendations:", error);
        if (container) {
            container.innerHTML = `<p class="text-center col-span-full text-red-500">Could not load recommendations.</p>`;
        }
    }
}

// ... (The rest of your ui.js file, including initUI, handleFormSubmit, etc., remains the same) ...
// --- Helper Functions ---
const getElement = (id) => document.getElementById(id);

function showNotification(message, isError = false) {
    const container = getElement('notification');
    if (!container) return;
    const bgColor = isError ? 'bg-red-500' : 'bg-green-500';
    container.innerHTML = `<div class="flex items-center text-white p-4 rounded-lg shadow-lg ${bgColor}"><i class="fas fa-check-circle mr-3"></i><p>${message}</p></div>`;
    container.classList.add('show');
    setTimeout(() => { container.classList.remove('show'); }, 4000);
}

// --- Card Rendering ---
function createListingCard(item) {
    const card = document.createElement('div');
    const pinnedClass = item.is_pinned ? 'border-2 border-indigo-400' : 'shadow-md';
    card.className = `stream-card bg-white rounded-lg overflow-hidden hover:shadow-xl transition duration-300 p-4 relative ${pinnedClass}`;
    card.innerHTML = `
        ${item.is_pinned ? '<div class="absolute top-2 right-2 text-xs bg-indigo-500 text-white px-2 py-1 rounded-full animate-pulse"><i class="fas fa-thumbtack mr-1"></i> Pinned</div>' : ''}
        <div class="mb-3"><h3 class="font-bold text-base">${item.title}</h3><div class="text-xs text-gray-500 mb-2 mt-1">From: <span class="font-semibold text-indigo-600">${item.source_name}</span></div></div>
        <p class="text-gray-700 text-sm mb-4">${item.description || ''}</p>
        <div class="flex justify-between items-center mt-auto"><span class="text-xs font-bold uppercase text-gray-400">${(item.category || '').replace('_', ' ')}</span><a href="${item.url}" target="_blank" rel="noopener noreferrer" class="bg-indigo-600 hover:bg-indigo-700 text-white px-3 py-1 rounded-full text-xs font-medium transition">Visit Site</a></div>
    `;
    return card;
}

// --- Core Logic ---
async function loadRecommendations() {
    const container = getElement('recommendations-container');
    if (!container) return;
    try {
        const response = await fetch(`${BACKEND_URL}/api/recommendations`);
        if (!response.ok) throw new Error(`Network Error: ${response.statusText}`);
        const listings = await response.json();
        container.innerHTML = '';
        if (listings.length === 0) {
            container.innerHTML = `<p class="text-center col-span-full text-gray-500">No recommendations available yet.</p>`;
            return;
        }
        listings.forEach(item => container.appendChild(createListingCard(item)));
    } catch (error) {
        container.innerHTML = `<p class="text-center col-span-full text-red-500">Could not load recommendations.</p>`;
    }
}

async function handleFormSubmit(event) {
    event.preventDefault();
    const form = event.target;
    const submitButton = getElement('submit-listing-btn');
    submitButton.disabled = true;
    submitButton.textContent = 'Submitting...';

    const listingData = Object.fromEntries(new FormData(form).entries());

    try {
        const response = await fetch(`${BACKEND_URL}/api/add-listing`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(listingData),
        });
        const result = await response.json();
        if (!response.ok) throw new Error(result.details || 'Submission failed.');

        showNotification('Success! Your recommendation has been added.');
        
        // --- BUG FIX: INSTANT UI UPDATE ---
        // 1. Create a new card with the data we just submitted.
        const newCard = createListingCard(listingData);
        // 2. Add it to the top of the list for an instant refresh.
        getElement('recommendations-container').prepend(newCard);
        // 3. Close the form.
        getElement('form-container').classList.add('hidden');
        getElement('form-chevron').classList.remove('rotate-180');
        
        form.reset();
        
    } catch (error) {
        showNotification(`Error: ${error.message}`, true);
    } finally {
        submitButton.disabled = false;
        submitButton.textContent = 'Submit Listing';
    }
}

// --- Initialization ---
export function initUI() {
    const addListingForm = getElement('add-listing-form');
    const toggleBtn = getElement('toggle-form-btn');
    const formContainer = getElement('form-container');
    const chevron = getElement('form-chevron');

    if (toggleBtn && formContainer && chevron) {
        toggleBtn.addEventListener('click', () => {
            formContainer.classList.toggle('hidden');
            chevron.classList.toggle('rotate-180');
        });
    }

    if (addListingForm) {
        addListingForm.addEventListener('submit', handleFormSubmit);
    }
    
    loadRecommendations();
}