Clone
<template>
  <div class="home">
    <h1>Student Assessment Portal</h1>
    <p>Select an assessment to begin:</p>

    <div class="assessment-list">
      <router-link
        v-for="assessment in allAssessments"
        :key="assessment.id"
        :to="`/${assessment.id}`"
        class="assessment-card"
      >
        <h3>{{ assessment.title }}</h3>
        <p>{{ assessment.description }}</p>
        <span v-if="assessment.isUploaded" class="uploaded-badge">Uploaded</span>
      </router-link>
    </div>

    <div class="upload-section">
      <h2>Create Custom Assessment</h2>
      
      <div class="instructions-box">
        <h3>How to Create AI-Generated Assessments</h3>
        <ol>
          <li>Download our <a href="/assessment-generation-instructions.md" download class="download-link">Assessment Generation Instructions</a></li>
          <li>Upload the instructions file to your AI chat (ChatGPT, Claude, etc.)</li>
          <li>Use one of the example prompts below (or create your own)</li>
          <li>Copy the generated JSON and paste it below</li>
        </ol>
      </div>

      <div class="input-methods">
        <div class="upload-container">
          <input 
            type="file" 
            ref="fileInput"
            @change="handleFileUpload"
            accept=".json"
            id="file-upload"
            class="file-input"
          />
          <label for="file-upload" class="file-label">
            <svg class="upload-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
              <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12"/>
            </svg>
            Upload JSON File
          </label>
        </div>
        
        <div class="divider">
          <span>OR</span>
        </div>
        
        <div class="paste-container">
          <textarea 
            v-model="pastedJson"
            placeholder="Paste your assessment JSON here..."
            class="json-textarea"
            rows="2"
          ></textarea>
          <button @click="handlePastedJson" class="submit-button">
            Create Assessment
          </button>
        </div>
      </div>

      <div class="example-prompts">
        <h3>Example Prompts</h3>
        <p class="prompts-description">Use these prompts with the instructions file for best results:</p>
        
        <div class="prompt-example">
          <div class="prompt-header">
            <h4>Environmental Science</h4>
            <button @click="copyToClipboard(simplePrompt1)" class="copy-button">Copy Prompt</button>
          </div>
          <pre>{{ simplePrompt1 }}</pre>
        </div>
        
        <div class="prompt-example">
          <div class="prompt-header">
            <h4>World History</h4>
            <button @click="copyToClipboard(simplePrompt2)" class="copy-button">Copy Prompt</button>
          </div>
          <pre>{{ simplePrompt2 }}</pre>
        </div>
        
        <div class="prompt-example">
          <div class="prompt-header">
            <h4>Mathematics</h4>
            <button @click="copyToClipboard(simplePrompt3)" class="copy-button">Copy Prompt</button>
          </div>
          <pre>{{ simplePrompt3 }}</pre>
        </div>
        
        <div class="prompt-example">
          <div class="prompt-header">
            <h4>Custom Subject</h4>
            <button @click="copyToClipboard(simplePromptCustom)" class="copy-button">Copy Prompt</button>
          </div>
          <pre>{{ simplePromptCustom }}</pre>
        </div>
      </div>

      <div v-if="uploadError" class="error-message">
        {{ uploadError }}
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'

const availableAssessments = ref([
  {
    id: '9th-grade-assessment-chatgpt',
    title: '9th Grade Readiness Assessment (ChatGPT)',
    description: 'Test your knowledge in History, Geography, Science, Math, and Language Arts'
  },
  {
    id: '9th-grade-assessment-grok',
    title: '9th Grade Readiness Assessment (Grok)',
    description: 'Alternative 9th grade assessment with different questions'
  },
  {
    id: '10th-grade-assessment',
    title: '10th Grade Readiness Assessment',
    description: 'Sample assessment for 10th grade students'
  }
])

const uploadedAssessments = ref([])
const uploadError = ref('')
const fileInput = ref(null)
const pastedJson = ref('')

const jsonStructure = `{
  "title": "Assessment title",
  "description": "Brief description",
  "subjects": [
    {
      "name": "Subject name",
      "questions": [
        {
          "id": unique number,
          "question": "Question text?",
          "options": ["Option A", "Option B", "Option C", "Option D"],
          "correctAnswer": index (0-3)
        }
      ]
    }
  ]
}`

const importantNotes = `IMPORTANT: 
- Each question must have exactly 4 options
- correctAnswer must be the array index (0-3) of the correct option
- All question IDs must be unique numbers
- Ensure the JSON is valid and properly formatted`

const sciencePrompt = `Create a JSON assessment file for Environmental Science suitable for high school students (grades 9-10).

The assessment should:
- Have 20 total questions
- Be divided into 4 subjects: Climate Change, Ecosystems, Pollution, and Conservation
- Include multiple choice questions only
- Cover basic concepts and current environmental issues
- Be at intermediate level

Format the output as a valid JSON file following this exact structure:
${jsonStructure}

${importantNotes}`

const mathPrompt = `Create a JSON assessment file for Algebra I suitable for 8th-9th grade students.

The assessment should:
- Have 24 total questions
- Be divided into 4 subjects: Linear Equations, Quadratic Functions, Systems of Equations, and Polynomials
- Include multiple choice questions only
- Include both conceptual and computational questions
- Be at intermediate level with some challenging problems

Format the output as a valid JSON file following this exact structure:
${jsonStructure}

${importantNotes}`

const languagePrompt = `Create a JSON assessment file for Spanish Language (Level 2) suitable for intermediate learners.

The assessment should:
- Have 20 total questions
- Be divided into 4 subjects: Vocabulary, Grammar, Reading Comprehension, and Cultural Knowledge
- Include multiple choice questions only
- Focus on present and past tenses, common vocabulary, and Hispanic culture
- Be at intermediate level

Format the output as a valid JSON file following this exact structure:
${jsonStructure}

${importantNotes}`

const customPrompt = `Create a JSON assessment file for [YOUR SUBJECT HERE] suitable for [YOUR AUDIENCE HERE].

The assessment should:
- Have [NUMBER] total questions
- Be divided into [NUMBER] subjects: [LIST YOUR TOPICS HERE]
- Include multiple choice questions only
- Cover [DESCRIBE WHAT TO COVER]
- Be at [DIFFICULTY LEVEL] level

Format the output as a valid JSON file following this exact structure:
${jsonStructure}

${importantNotes}`

// Simplified prompts for use with the instructions file
const simplePrompt1 = `Create an assessment file for Environmental Science suitable for high school students (grades 9-10).

The assessment should:
- Have 20 total questions
- Be divided into 4 subjects: Climate Change, Ecosystems, Pollution, and Conservation
- Include multiple choice questions only
- Cover basic concepts and current environmental issues
- Be at intermediate level

Follow the attached assessment generation instructions.`

const simplePrompt2 = `Create an assessment file for World History focusing on Ancient Civilizations for middle school students.

The assessment should:
- Have 24 total questions
- Cover these civilizations: Ancient Egypt, Ancient Greece, Ancient Rome, and Ancient China
- Include questions about government, culture, achievements, and key historical figures
- Be at beginner to intermediate level

Follow the attached assessment generation instructions.`

const simplePrompt3 = `Create an assessment file for Algebra I suitable for 8th-9th grade students.

The assessment should:
- Have 20 total questions
- Cover 4 topics: Linear Equations, Polynomials, Factoring, and Quadratic Equations
- Focus on problem-solving and application
- Be at intermediate level

Follow the attached assessment generation instructions.`

const simplePromptCustom = `Create an assessment file for [YOUR SUBJECT] suitable for [TARGET AUDIENCE].

The assessment should:
- Have [NUMBER] total questions
- Cover these topics: [LIST TOPICS]
- Include [SPECIFY QUESTION TYPES OR FOCUS]
- Be at [DIFFICULTY] level

Follow the attached assessment generation instructions.`

const allAssessments = computed(() => {
  return [...availableAssessments.value, ...uploadedAssessments.value]
})

const loadUploadedAssessments = () => {
  const stored = localStorage.getItem('uploadedAssessments')
  if (stored) {
    try {
      uploadedAssessments.value = JSON.parse(stored)
    } catch (e) {
      console.error('Failed to load uploaded assessments:', e)
    }
  }
}

const validateAssessment = (data) => {
  if (!data.title || !data.description || !data.subjects) {
    throw new Error('Assessment must have title, description, and subjects')
  }
  
  if (!Array.isArray(data.subjects) || data.subjects.length === 0) {
    throw new Error('Assessment must have at least one subject')
  }
  
  for (const subject of data.subjects) {
    if (!subject.name || !subject.questions || !Array.isArray(subject.questions)) {
      throw new Error('Each subject must have a name and questions array')
    }
    
    for (const question of subject.questions) {
      if (!question.id || !question.question || !question.options || typeof question.correctAnswer !== 'number') {
        throw new Error('Each question must have id, question text, options, and correctAnswer')
      }
      
      if (!Array.isArray(question.options) || question.options.length < 2) {
        throw new Error('Each question must have at least 2 options')
      }
      
      if (question.correctAnswer < 0 || question.correctAnswer >= question.options.length) {
        throw new Error('correctAnswer must be a valid index for the options array')
      }
    }
  }
  
  return true
}

const createAssessment = (data) => {
  const assessmentId = `uploaded-${Date.now()}`
  const assessment = {
    id: assessmentId,
    title: data.title,
    description: data.description,
    isUploaded: true
  }
  
  // Store the full assessment data in localStorage
  localStorage.setItem(`assessment-${assessmentId}`, JSON.stringify(data))
  
  // Add to uploaded assessments list
  uploadedAssessments.value.push(assessment)
  
  // Save the list of uploaded assessments
  localStorage.setItem('uploadedAssessments', JSON.stringify(uploadedAssessments.value))
  
  return assessment
}

const handleFileUpload = async (event) => {
  uploadError.value = ''
  const file = event.target.files[0]
  
  if (!file) return
  
  try {
    const text = await file.text()
    const data = JSON.parse(text)
    
    validateAssessment(data)
    createAssessment(data)
    
    // Clear the file input
    if (fileInput.value) {
      fileInput.value.value = ''
    }
    
    uploadError.value = ''
    
  } catch (error) {
    uploadError.value = error.message || 'Failed to parse JSON file'
    console.error('Upload error:', error)
  }
}

const handlePastedJson = () => {
  uploadError.value = ''
  
  if (!pastedJson.value.trim()) {
    uploadError.value = 'Please paste JSON content'
    return
  }
  
  try {
    const data = JSON.parse(pastedJson.value)
    validateAssessment(data)
    createAssessment(data)
    
    // Clear the textarea
    pastedJson.value = ''
    uploadError.value = ''
    
    // Switch to upload tab to show success
    activeTab.value = 'upload'
    
  } catch (error) {
    uploadError.value = error.message || 'Failed to parse JSON content'
    console.error('Paste error:', error)
  }
}

const copyToClipboard = async (text) => {
  try {
    await navigator.clipboard.writeText(text)
    // You could add a success notification here
  } catch (err) {
    console.error('Failed to copy:', err)
    // Fallback for older browsers
    const textArea = document.createElement('textarea')
    textArea.value = text
    textArea.style.position = 'fixed'
    textArea.style.left = '-999999px'
    document.body.appendChild(textArea)
    textArea.select()
    try {
      document.execCommand('copy')
    } catch (err) {
      console.error('Fallback copy failed:', err)
    }
    document.body.removeChild(textArea)
  }
}

onMounted(() => {
  loadUploadedAssessments()
})
</script>

<style scoped>
.home {
  max-width: 800px;
  margin: 0 auto;
  padding: 2rem;
}

h1 {
  color: #2c3e50;
  margin-bottom: 1rem;
  text-align: center;
}

p {
  text-align: center;
  margin-bottom: 2rem;
  color: #666;
}

.assessment-list {
  display: grid;
  gap: 1rem;
}

.assessment-card {
  display: block;
  padding: 1.5rem;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  text-decoration: none;
  color: inherit;
  transition: transform 0.2s, box-shadow 0.2s;
}

.assessment-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}

.assessment-card h3 {
  color: #2c3e50;
  margin-bottom: 0.5rem;
}

.assessment-card p {
  color: #666;
  margin: 0;
  text-align: left;
}

.assessment-card {
  position: relative;
}

.uploaded-badge {
  position: absolute;
  top: 1rem;
  right: 1rem;
  background: #42b883;
  color: white;
  padding: 0.25rem 0.5rem;
  border-radius: 4px;
  font-size: 0.75rem;
  font-weight: bold;
}

.upload-section {
  margin-top: 3rem;
  padding: 2rem;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.upload-section h2 {
  color: #2c3e50;
  margin-bottom: 0.5rem;
}

.upload-section p {
  color: #666;
  margin-bottom: 1.5rem;
}


.file-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

.file-label {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 1rem 1.5rem;
  background: #42b883;
  color: white;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.2s;
  font-weight: 500;
}

.file-label:hover {
  background: #35a372;
}

.error-message {
  color: #dc3545;
  padding: 0.75rem;
  background: #f8d7da;
  border: 1px solid #f5c6cb;
  border-radius: 4px;
  margin-top: 1rem;
}

.instructions-box {
  background: #f0f9ff;
  border: 2px solid #42b883;
  border-radius: 8px;
  padding: 1.5rem;
  margin-bottom: 2rem;
}

.instructions-box h3 {
  margin: 0 0 1rem 0;
  color: #2c3e50;
}

.instructions-box ol {
  margin: 0;
  padding-left: 1.5rem;
  color: #495057;
  line-height: 1.8;
}

.instructions-box li {
  margin-bottom: 0.5rem;
}

.input-methods {
  margin-bottom: 3rem;
}

.upload-container {
  width: 100%;
  text-align: center;
  margin-bottom: 1.5rem;
}

.divider {
  text-align: center;
  margin: 1.5rem 0;
  position: relative;
}

.divider::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 1px;
  background: #e0e0e0;
}

.divider span {
  background: white;
  padding: 0 1rem;
  position: relative;
  color: #999;
  font-weight: 600;
  text-transform: uppercase;
  font-size: 0.875rem;
}

.paste-container {
  display: flex;
  gap: 1rem;
  align-items: center;
}

.upload-icon {
  width: 20px;
  height: 20px;
  margin-right: 0.5rem;
  vertical-align: middle;
}

.json-textarea {
  flex: 1;
  padding: 0.75rem;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-family: 'Courier New', monospace;
  font-size: 0.9rem;
  resize: none;
  line-height: 1.5;
}

.submit-button {
  padding: 0.75rem 1.5rem;
  background: #42b883;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 1rem;
  transition: background-color 0.2s;
}

.submit-button:hover {
  background: #35a372;
}

.example-prompts {
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 2px solid #e0e0e0;
}

.example-prompts h3 {
  color: #2c3e50;
  margin-bottom: 0.5rem;
}

.prompts-description {
  color: #666;
  margin-bottom: 2rem;
}

.instructions {
  background: #f0f9ff;
  padding: 1rem;
  border-radius: 4px;
  margin-bottom: 1.5rem;
}

.instructions p {
  margin: 0.5rem 0;
  color: #666;
}

.instructions ol {
  margin: 0.5rem 0;
  padding-left: 1.5rem;
  color: #666;
}

.instructions li {
  margin: 0.5rem 0;
}

.download-link {
  color: #42b883;
  text-decoration: none;
  font-weight: 600;
}

.download-link:hover {
  text-decoration: underline;
}


.prompt-example {
  margin-bottom: 2rem;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  overflow: hidden;
}


.prompt-header {
  background: #f8f9fa;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid #e0e0e0;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.prompt-example h4 {
  margin: 0;
  color: #2c3e50;
  font-size: 1.1rem;
}

.copy-button {
  padding: 0.5rem 1rem;
  background: #42b883;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 0.875rem;
  transition: background-color 0.2s;
  float: right;
  margin-left: 1rem;
}

.copy-button:hover {
  background: #35a372;
}

.prompt-example pre {
  margin: 0;
  padding: 1rem;
  background: #f8f9fa;
  overflow-x: auto;
  font-family: 'Courier New', monospace;
  font-size: 0.875rem;
  line-height: 1.5;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.tips {
  background: #f0f9ff;
  padding: 1rem;
  border-radius: 4px;
  margin-top: 1.5rem;
}

.tips h4 {
  color: #2c3e50;
  margin-bottom: 0.5rem;
}

.tips ul {
  margin: 0;
  padding-left: 1.5rem;
  color: #666;
}

.tips li {
  margin-bottom: 0.25rem;
}

@media (max-width: 768px) {
  .paste-container {
    flex-direction: column;
    gap: 0.5rem;
  }
  
  .json-textarea {
    width: 100%;
  }
  
  .example-prompts {
    margin-top: 2rem;
  }
}
</style>