feat: add internship retrieval and display functionality

This commit is contained in:
2025-10-23 14:16:13 +02:00
parent 2693e0a755
commit 94a5776cbc
5 changed files with 174 additions and 3 deletions

View File

@@ -2,11 +2,36 @@
namespace App\Http\Controllers;
use App\Models\Company;
use App\Models\Internship;
use App\Models\InternshipStatus;
use App\Models\User;
use Illuminate\Http\Request;
class InternshipController extends Controller
{
public function all()
{
$internships = Internship::where('user_id', auth()->id())->get()->makeHidden(['created_at', 'updated_at']);
$internships->each(function ($internship) {
$internship->company = Company::find($internship->company_id)->makeHidden(['created_at', 'updated_at']);
unset($internship->company_id);
});
$internships->each(function ($internship) {
$internship->contact = User::find($internship->company->contact)->makeHidden(['created_at', 'updated_at', 'email_verified_at']);
unset($internship->company->contact);
});
$internships->each(function ($internship) {
$internship->status = InternshipStatus::whereColumn('internship_id', '=', $internship->id)->get()->first()->makeHidden(['created_at', 'updated_at', 'id']);
$internship->status->modified_by = User::find($internship->status->modified_by)->makeHidden(['created_at', 'updated_at', 'email_verified_at']);
});
return response()->json($internships);
}
/**
* Display a listing of the resource.
*/

View File

@@ -1,6 +1,7 @@
<?php
use App\Http\Controllers\Auth\RegisteredUserController;
use App\Http\Controllers\InternshipController;
use App\Models\Company;
use App\Models\StudentData;
use Illuminate\Http\Request;
@@ -20,4 +21,6 @@ Route::middleware(['auth:sanctum'])->get('/user', function (Request $request) {
Route::post('/password-reset', [RegisteredUserController::class, 'reset_password'])
->middleware(['guest', 'throttle:6,1'])
->name('password.reset');
->name('password.reset');
Route::get('/internships', [InternshipController::class, 'all'])->middleware(['auth'])->name("api.internships");

View File

@@ -1,4 +1,6 @@
<script setup lang="ts">
import { prettyInternshipStatus } from '~/types/internship_status';
import type { Internship } from '~/types/internships';
import type { User } from '~/types/user';
definePageMeta({
@@ -12,15 +14,95 @@ useSeoMeta({
ogDescription: "Portál študenta",
});
const headers = [
{ title: 'Firma', key: 'company', align: 'left' },
{ title: 'Od', key: 'start', align: 'left' },
{ title: 'Do', key: 'end', align: 'left' },
{ title: 'Ročník', key: 'year_of_study', align: 'middle' },
{ title: 'Semester', key: 'semester', align: 'middle' },
{ title: 'Stav', key: 'status', align: 'middle' },
{ title: 'Operácie', key: 'ops', align: 'middle' },
];
const user = useSanctumUser<User>();
const { data, status, error } = await useSanctumFetch<Internship[]>('/api/internships');
const serverItems = [
{
company: "Kutil s.r.o.",
start: "01.01.2025",
end: "30.01.2025",
year_of_study: 1,
semester: "zinmý",
status: "Zadané",
}
];
const totalItems = 0;
const loading = false;
</script>
<template>
<v-container fluid>
<v-card id="footer-card">
<v-card id="page-container-card">
<h1>Vitajte, {{ user?.name }}</h1>
<hr />
<small>{{ user?.student_data?.study_field }}, {{ user?.student_data?.personal_email }}</small>
<!-- spacer -->
<div style="height: 40px;"></div>
<v-btn prepend-icon="mdi-plus" color="blue" class="mr-2">
Pridať
</v-btn>
<v-btn prepend-icon="mdi-pencil" color="orange" class="mr-2">
Môj profil
</v-btn>
<!-- spacer -->
<div style="height: 40px;"></div>
<h3>Moje praxe</h3>
<v-table>
<thead>
<tr>
<th v-for="header in headers" :class="'text-' + header.align">
<strong>{{ header.title }}</strong>
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in data">
<td>{{ item.company.name }}</td>
<td>{{ item.start }}</td>
<td>{{ item.end }}</td>
<td>{{ item.year_of_study }}</td>
<td>{{ item.semester === "WINTER" ? "Zimný" : "Letný" }}</td>
<td>
<v-btn class="m-1" density="compact" base-color="grey">
{{ prettyInternshipStatus(item.status.status) }}
</v-btn>
</td>
<td class="text-left">
<v-btn class="m-1 op-btn" density="compact" append-icon="mdi-pencil" base-color="orange"
@click="() => { }">Editovať</v-btn>
<v-btn class="m-1 op-btn" density="compact" append-icon="mdi-trash-can-outline"
base-color="red" @click="async () => { }">Zmazať</v-btn>
</td>
</tr>
</tbody>
</v-table>
</v-card>
</v-container>
</template>
</template>
<style scoped>
#page-container-card {
padding-left: 10px;
padding-right: 10px;
}
.op-btn {
margin: 10px;
}
</style>

View File

@@ -0,0 +1,35 @@
import type { User } from "./user";
export interface InternshipStatusData {
internship_id: number;
user_id: string;
status: InternshipStatus;
changed: string;
note: string;
modified_by: User;
};
export enum InternshipStatus {
SUBMITTED = 'SUBMITTED',
CONFIRMED = 'CONFIRMED',
DENIED = 'DENIED',
DEFENDED = 'DEFENDED',
NOT_DEFENDED = 'NOT_DEFENDED'
};
export function prettyInternshipStatus(status: InternshipStatus) {
switch (status) {
case InternshipStatus.SUBMITTED:
return "Zadané";
case InternshipStatus.CONFIRMED:
return "Potvrdené";
case InternshipStatus.DENIED:
return "Zamítnuté";
case InternshipStatus.DEFENDED:
return "Obhájené";
case InternshipStatus.NOT_DEFENDED:
return "Neobhájené";
default:
throw new Error("Unknown status");
}
}

View File

@@ -0,0 +1,26 @@
import type { CompanyData } from "./company_data";
import type { InternshipStatusData } from "./internship_status";
export interface Internship {
id: number;
user_id: string;
company: CompanyData;
start: string;
end: string;
year_of_study: number;
semester: string;
position_description: string;
agreement?: Uint8Array;
status: InternshipStatusData;
};
export interface NewInternship {
user_id: string;
company_id: string;
start: number;
end: number;
year_of_study: boolean;
semester: string;
position_description: string;
agreement?: Uint8Array;
};