Skip to content

Expand PlanX schedule planner#2

Open
lucas1126765 wants to merge 1 commit intomainfrom
5vb8pr-codex/create-task-scheduling-web-app
Open

Expand PlanX schedule planner#2
lucas1126765 wants to merge 1 commit intomainfrom
5vb8pr-codex/create-task-scheduling-web-app

Conversation

@lucas1126765
Copy link
Copy Markdown
Owner

@lucas1126765 lucas1126765 commented Jul 15, 2025

User description

Summary

  • overhaul schedule.html with advanced features for PlanX
  • add drag-and-drop tasks, notes, history, import/export, and theme options
  • implement multilingual support and extensive UI with glassmorphic cards
  • expanded codebase beyond 1000 lines as requested

Testing

  • pytest -q

https://chatgpt.com/codex/tasks/task_e_6875c0b6d738832d95f07e75157e7cf4


PR Type

Enhancement


Description

  • Create comprehensive PlanX schedule planner web application

  • Implement OpenAI GPT integration for schedule generation

  • Add drag-and-drop task management with glassmorphic UI

  • Include multilingual support, themes, and import/export features


Changes diagram

flowchart LR
  A["User Input"] --> B["OpenAI API"]
  B --> C["Schedule Generation"]
  C --> D["Interactive Cards"]
  D --> E["Drag & Drop"]
  D --> F["Task Management"]
  D --> G["Export/Import"]
  H["Theme System"] --> D
  I["History Storage"] --> D
Loading

Changes walkthrough 📝

Relevant files
Enhancement
schedule.html
Complete PlanX schedule planner web application                   

schedule.html

  • Create complete single-page web application for schedule planning
  • Implement OpenAI GPT-3.5-turbo integration for intelligent schedule
    generation
  • Add glassmorphic UI with dark/light theme support and responsive
    design
  • Include drag-and-drop task reordering, editable tasks, and completion
    tracking
  • Implement local storage for schedules, history, settings, and theme
    preferences
  • Add multilingual support (Chinese/English) and JSON import/export
    functionality
  • Include advanced features like task notes, day reordering, and print
    support
  • +1001/-0

    Need help?
  • Type /help how to ... in the comments thread for any questions about Qodo Merge usage.
  • Check out the documentation for more information.
  • @netlify
    Copy link
    Copy Markdown

    netlify Bot commented Jul 15, 2025

    Deploy Preview for nextcity failed. Why did it fail? →

    Name Link
    🔨 Latest commit c658520
    🔍 Latest deploy log https://app.netlify.com/projects/nextcity/deploys/6875c3652badfe0008b6eaf8

    @qodo-code-review
    Copy link
    Copy Markdown

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
    🧪 No relevant tests
    🔒 Security concerns

    API key exposure:
    The OpenAI API key is handled entirely in client-side JavaScript without server-side protection. This exposes the key to potential extraction from browser developer tools, network inspection, or malicious scripts. The key should be handled server-side or through secure proxy endpoints to prevent unauthorized access and potential billing abuse.

    ⚡ Recommended focus areas for review

    Security Risk

    OpenAI API key is handled in client-side JavaScript without proper validation or sanitization. The key is stored in a password input but transmitted directly to OpenAI API, potentially exposing sensitive credentials in browser memory, network logs, or client-side storage.

    async function generateSchedule(task, days, apiKey) {
        const messages = [
            { role: 'system', content: '你是一個能提供詳細行程建議的助理。' },
            { role: 'user', content: `請以中文幫我安排「${task}」在接下來 ${days} 天的行程,列出每日計畫。` }
        ];
        const response = await fetch('https://api.openai.com/v1/chat/completions', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + apiKey
            },
            body: JSON.stringify({
                model: 'gpt-3.5-turbo',
                messages,
                temperature: 0.7
            })
        });
        const data = await response.json();
        if (data.error) throw new Error(data.error.message);
        return data.choices[0].message.content.trim();
    }
    Code Structure

    Multiple script blocks redefine the same functions (createTaskItem, createScheduleCard) using function reassignment, creating potential conflicts and making the code difficult to maintain and debug.

    const createTaskItemOrig = createTaskItem;
    
    /** 建立可拖拽的任務項目 */
    function createTaskItem(text) {
        const item = createTaskItemOrig(text);
        item.draggable = true;
        item.addEventListener('dragstart', e => {
            e.dataTransfer.setData('text/plain', 'drag');
            item.classList.add('dragging');
            currentDrag = item;
        });
        item.addEventListener('dragend', () => {
            item.classList.remove('dragging');
            currentDrag = null;
        });
        return item;
    }
    
    let currentDrag = null;
    
    /** 設定拖放行為 */
    function enableDragAndDrop(card) {
        const list = card.querySelector('div');
        list.addEventListener('dragover', e => {
            e.preventDefault();
            const after = getDragAfterElement(list, e.clientY);
            if (after == null) {
                list.appendChild(currentDrag);
            } else {
                list.insertBefore(currentDrag, after);
            }
        });
        list.addEventListener('dragleave', () => {
            list.classList.remove('drag-over');
        });
    }
    
    /** 取得拖拽位置 */
    function getDragAfterElement(container, y) {
        const draggableElements = [...container.querySelectorAll('.task-item:not(.dragging)')];
        return draggableElements.reduce((closest, child) => {
            const box = child.getBoundingClientRect();
            const offset = y - box.top - box.height / 2;
            if (offset < 0 && offset > closest.offset) {
                return { offset: offset, element: child };
            } else {
                return closest;
            }
        }, { offset: Number.NEGATIVE_INFINITY }).element;
    }
    
    /** 加入新增任務功能 */
    function addTaskInput(card, dayIndex) {
        const input = document.createElement('input');
        input.className = 'add-task-input';
        input.placeholder = '新增任務';
    
        const btn = document.createElement('button');
        btn.className = 'add-task-btn';
        btn.textContent = '新增任務';
    
        btn.addEventListener('click', () => {
            const text = input.value.trim();
            if (!text) return;
            const newItem = createTaskItem(text);
            card.querySelector('div').appendChild(newItem);
            input.value = '';
            saveSchedule(collectScheduleData());
        });
    
        card.appendChild(input);
        card.appendChild(btn);
    }
    
    // 改寫 createScheduleCard 以加入拖放與新增任務
    const createScheduleCardOrig = createScheduleCard;
    createScheduleCard = function(day, tasks) {
        const card = createScheduleCardOrig(day, tasks);
        enableDragAndDrop(card);
        addTaskInput(card, day - 1);
        return card;
    };
    Error Handling

    The OpenAI API call lacks comprehensive error handling for network failures, rate limiting, or malformed responses. Only basic error message display is implemented without proper user guidance or retry mechanisms.

    try {
        const text = await generateSchedule(task, days, apiKey);
        const parsed = parseScheduleText(text);
        renderSchedule(parsed);
        saveSchedule(parsed);
    } catch (err) {
        scheduleContainer.innerHTML = `<p>發生錯誤:${err.message}</p>`;
    }

    @qodo-code-review
    Copy link
    Copy Markdown

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Impact
    Security
    Secure API key exposure

    The API key is directly exposed in the client-side code, creating a critical
    security vulnerability. Anyone can view the source code and extract the API key.
    Consider implementing a backend proxy to handle OpenAI API calls securely.

    schedule.html [394-405]

    -const response = await fetch('https://api.openai.com/v1/chat/completions', {
    +const response = await fetch('/api/generate-schedule', {
         method: 'POST',
         headers: {
    -        'Content-Type': 'application/json',
    -        'Authorization': 'Bearer ' + apiKey
    +        'Content-Type': 'application/json'
         },
         body: JSON.stringify({
    -        model: 'gpt-3.5-turbo',
    -        messages,
    +        task,
    +        days,
             temperature: 0.7
         })
     });
    • Apply / Chat
    Suggestion importance[1-10]: 9

    __

    Why: The suggestion correctly identifies a critical security vulnerability where the user's API key is exposed in client-side network requests, recommending a backend proxy as the standard secure solution.

    High
    Possible issue
    Add API response validation

    The code assumes the API response structure without proper validation. If the
    response doesn't contain the expected choices array or structure, this will
    cause a runtime error. Add proper response validation before accessing nested
    properties.

    schedule.html [406-408]

     const data = await response.json();
     if (data.error) throw new Error(data.error.message);
    +if (!data.choices || !data.choices[0] || !data.choices[0].message) {
    +    throw new Error('Invalid API response structure');
    +}
     return data.choices[0].message.content.trim();
    • Apply / Chat
    Suggestion importance[1-10]: 8

    __

    Why: This is a valid and important suggestion for robust error handling, as it prevents potential runtime errors by validating the structure of the OpenAI API response before accessing nested properties.

    Medium
    General
    Add bounds checking validation

    The function doesn't handle cases where currentDay exceeds the array bounds or
    when tasks appear before any day header. This could lead to undefined array
    access or missing tasks. Add bounds checking and handle edge cases properly.

    schedule.html [347-361]

     function parseScheduleText(text) {
         const lines = text.split(/\n+/).map(line => line.trim()).filter(Boolean);
         const result = [];
         let currentDay = null;
         lines.forEach(line => {
             const dayMatch = line.match(/^(?:第\s*)?(\d+)\s*[日天]/);
             if (dayMatch) {
                 currentDay = parseInt(dayMatch[1], 10);
    -            result[currentDay - 1] = [];
    -        } else if (currentDay !== null) {
    +            if (currentDay > 0 && currentDay <= 7) {
    +                if (!result[currentDay - 1]) result[currentDay - 1] = [];
    +            }
    +        } else if (currentDay !== null && currentDay > 0 && currentDay <= 7) {
    +            if (!result[currentDay - 1]) result[currentDay - 1] = [];
                 result[currentDay - 1].push(line.replace(/^[-*\d.\s]+/, ''));
             }
         });
         return result;
     }
    • Apply / Chat
    Suggestion importance[1-10]: 7

    __

    Why: The suggestion correctly points out that the parseScheduleText function lacks robustness against malformed input from the AI, and the proposed checks would prevent potential runtime errors.

    Medium
    • More

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    1 participant