Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions app/Http/Controllers/Student/DashboardController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace App\Http\Controllers\Student;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;

class DashboardController extends Controller
{
public function index()
{
$user = Auth::user();
return response()->json($user);
}
}
31 changes: 31 additions & 0 deletions app/Http/Controllers/Student/DiscussionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace App\Http\Controllers\Student;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\Discussion;

class DiscussionController extends Controller
{
public function index()
{
$messages = Discussion::with('user')->latest()->get();
return response()->json(['messages' => $messages]);
}

public function store(Request $request)
{
$request->validate([
'message' => 'required|string|max:1000',
]);

Discussion::create([
'user_id' => Auth::id(),
'message' => $request->message,
]);

return response()->json(['message' => 'Message posted.']);
}
}
15 changes: 15 additions & 0 deletions app/Http/Controllers/Student/FeedbackController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace App\Http\Controllers\Student;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;

class FeedbackController extends Controller
{
public function index()
{
$feedback = Auth::user()->works()->with('feedback')->get();
return response()->json(['feedback' => $feedback]);
}
}
30 changes: 30 additions & 0 deletions app/Http/Controllers/Student/ProfileController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace App\Http\Controllers\Student;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class ProfileController extends Controller
{
public function edit()
{
return response()->json(Auth::user());
}

public function update(Request $request)
{
$user = Auth::user();

$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email,' . $user->id,
'phone' => 'nullable|string|max:20',
]);

$user->update($request->only('name', 'email', 'phone'));

return response()->json(['message' => 'Profile updated successfully.']);
}
}
34 changes: 34 additions & 0 deletions app/Http/Controllers/Student/SubmissionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace App\Http\Controllers\Student;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class SubmissionController extends Controller
{
public function index()
{
$user = Auth::user();
$work = $user->works()->latest()->first();
return response()->json(['work' => $work]);
}

public function store(Request $request)
{
$request->validate([
'title' => 'required|string|max:255',
'file' => 'required|file|mimes:pdf,zip|max:10240', // 10MB
]);

$path = $request->file('file')->store('submissions');

$work = $request->user()->works()->create([
'title' => $request->title,
'file_path' => $path,
]);

return response()->json(['message' => 'Submission uploaded successfully.']);
}
}
47 changes: 47 additions & 0 deletions app/Http/Kernel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
protected \$middleware = [
// Global middleware
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];

protected \$middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],

'api' => [
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];

protected \$routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'role' => \App\Http\Middleware\RoleMiddleware::class, // custom role middleware
];
}
19 changes: 19 additions & 0 deletions app/Http/Middleware/RoleMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// app/Http/Middleware/RoleMiddleware.php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class RoleMiddleware
{
public function handle(Request $request, Closure $next, $role)
{
if (!Auth::check() || Auth::user()->role !== $role) {
abort(403, 'Unauthorized.');
}

return $next($request);
}
}
15 changes: 15 additions & 0 deletions app/Models/Discussion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// app/Models/Discussion.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Discussion extends Model
{
protected $fillable = ['user_id', 'message'];

public function user()
{
return $this->belongsTo(User::class);
}
}
20 changes: 20 additions & 0 deletions app/Models/Work.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// app/Models/Work.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Work extends Model
{
protected $fillable = ['title', 'file_path', 'user_id'];

public function user()
{
return $this->belongsTo(User::class);
}

public function feedback()
{
return $this->hasOne(Feedback::class);
}
}
18 changes: 18 additions & 0 deletions resources/js/Pages/Student/Dashboard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<template>
<div class="p-4">
<h1 class="text-2xl font-bold mb-4">Welcome, {{ user.name }}</h1>
<p class="text-gray-600">Check your competition status, deadlines, and announcements.</p>
</div>
</template>

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

const user = ref({})

onMounted(async () => {
const response = await axios.get('/api/user')
user.value = response.data
})
</script>
40 changes: 40 additions & 0 deletions resources/js/Pages/Student/Discussion.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<template>
<div class="p-4">
<h2 class="text-xl font-semibold mb-4">Discussion Board</h2>
<form @submit.prevent="postMessage" class="flex items-center space-x-2 mb-4">
<input v-model="newMessage" placeholder="Write a message..." class="flex-1 input" />
<button class="btn-primary">Send</button>
</form>
<div class="space-y-3">
<div v-for="msg in messages" :key="msg.id" class="bg-gray-100 p-3 rounded">
<p class="font-semibold">{{ msg.user.name }}</p>
<p>{{ msg.message }}</p>
<p class="text-xs text-gray-500">{{ formatTime(msg.created_at) }}</p>
</div>
</div>
</div>
</template>

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

const messages = ref([])
const newMessage = ref('')

const fetchMessages = async () => {
const res = await axios.get('/student/discussion')
messages.value = res.data.messages || []
}

const postMessage = async () => {
if (!newMessage.value.trim()) return
await axios.post('/student/discussion', { message: newMessage.value })
newMessage.value = ''
await fetchMessages()
}

const formatTime = (timestamp) => new Date(timestamp).toLocaleString()

onMounted(fetchMessages)
</script>
25 changes: 25 additions & 0 deletions resources/js/Pages/Student/Feedback.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<template>
<div class="p-4">
<h2 class="text-xl font-semibold mb-4">Your Feedback</h2>
<div v-if="feedback.length === 0">No feedback available yet.</div>
<div v-else class="space-y-4">
<div v-for="f in feedback" :key="f.id" class="p-4 bg-gray-100 rounded">
<h3 class="font-semibold">{{ f.title }}</h3>
<p>{{ f.feedback.comment }}</p>
<p class="text-sm text-gray-500">Score: {{ f.feedback.score }}</p>
</div>
</div>
</div>
</template>

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

const feedback = ref([])

onMounted(async () => {
const res = await axios.get('/student/feedback')
feedback.value = res.data.feedback || []
})
</script>
30 changes: 30 additions & 0 deletions resources/js/Pages/Student/Profile.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<template>
<div class="p-4 max-w-md">
<h2 class="text-xl font-semibold mb-4">Edit Profile</h2>
<form @submit.prevent="updateProfile" class="space-y-4">
<input v-model="form.name" type="text" placeholder="Name" class="input" required />
<input v-model="form.email" type="email" placeholder="Email" class="input" required />
<input v-model="form.phone" type="text" placeholder="Phone (optional)" class="input" />
<button class="btn-primary">Save Changes</button>
<p v-if="message" class="text-green-600 mt-2">{{ message }}</p>
</form>
</div>
</template>

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

const form = ref({ name: '', email: '', phone: '' })
const message = ref('')

onMounted(async () => {
const res = await axios.get('/api/user')
form.value = res.data
})

const updateProfile = async () => {
const res = await axios.post('/student/profile', form.value)
message.value = res.data.message || 'Profile updated.'
}
</script>
29 changes: 29 additions & 0 deletions resources/js/Pages/Student/Submission.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template>
<div class="p-4">
<h2 class="text-xl font-semibold mb-4">Submit Your Project</h2>
<form @submit.prevent="submitForm" class="space-y-4">
<input v-model="title" type="text" placeholder="Project Title" class="input" required />
<input ref="fileInput" type="file" class="input" required />
<button class="btn-primary">Upload</button>
<p v-if="message" class="text-green-600 mt-2">{{ message }}</p>
</form>
</div>
</template>

<script setup>
import { ref } from 'vue'
import axios from 'axios'

const title = ref('')
const fileInput = ref(null)
const message = ref('')

const submitForm = async () => {
const formData = new FormData()
formData.append('title', title.value)
formData.append('file', fileInput.value.files[0])

const res = await axios.post('/student/submission', formData)
message.value = res.data.message || 'Uploaded successfully.'
}
</script>
Loading