jobs/src/views/Dashboard.vue

472 lines
11 KiB
Vue
Raw Normal View History

2025-03-30 11:52:59 +00:00
<script setup>
import { ref } from 'vue';
// Sample dashboard data
const stats = ref({
applications: 12,
interviews: 4,
offers: 1,
savedJobs: 8
});
const recentActivity = ref([
{
id: 1,
type: 'application',
company: 'Tech Innovations Inc.',
position: 'Frontend Developer',
date: '2025-03-28',
status: 'Applied'
},
{
id: 2,
type: 'interview',
company: 'DataSystems Co.',
position: 'Backend Engineer',
date: '2025-03-25',
status: 'Interview Scheduled'
},
{
id: 3,
type: 'saved',
company: 'WebSolutions Ltd.',
position: 'Full Stack Developer',
date: '2025-03-23',
status: 'Saved'
},
{
id: 4,
type: 'offer',
company: 'Digital Creations',
position: 'UI/UX Designer',
date: '2025-03-20',
status: 'Offer Received'
}
]);
const upcomingEvents = ref([
{
id: 1,
title: 'Technical Interview',
company: 'DataSystems Co.',
date: '2025-04-02',
time: '10:00 AM'
},
{
id: 2,
title: 'Coding Challenge Due',
company: 'Tech Innovations Inc.',
date: '2025-04-05',
time: '11:59 PM'
},
{
id: 3,
title: 'Follow-up Call',
company: 'Digital Creations',
date: '2025-04-07',
time: '2:30 PM'
}
]);
const recommendedJobs = ref([
{
id: 1,
title: 'Senior Vue Developer',
company: 'InnovateTech Solutions',
location: 'Remote',
salary: '$140,000 - $170,000',
matchScore: 95
},
{
id: 2,
title: 'Frontend Team Lead',
company: 'WebWorks Inc.',
location: 'San Francisco, CA',
salary: '$160,000 - $190,000',
matchScore: 88
},
{
id: 3,
title: 'Full Stack Engineer',
company: 'CloudSystems',
location: 'New York, NY',
salary: '$130,000 - $160,000',
matchScore: 82
}
]);
</script>
<template>
<div class="dashboard">
<div class="dashboard-grid">
<!-- Stats Cards -->
<div class="stats-container">
<div class="stat-card">
<div class="stat-value">{{ stats.applications }}</div>
<div class="stat-label">Applications</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ stats.interviews }}</div>
<div class="stat-label">Interviews</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ stats.offers }}</div>
<div class="stat-label">Offers</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ stats.savedJobs }}</div>
<div class="stat-label">Saved Jobs</div>
</div>
</div>
<!-- Recent Activity -->
<div class="dashboard-card activity-card">
<h3 class="card-title">Recent Activity</h3>
<div class="activity-list">
<div v-for="activity in recentActivity" :key="activity.id" class="activity-item">
<div class="activity-icon" :class="activity.type">
<span v-if="activity.type === 'application'">📝</span>
<span v-else-if="activity.type === 'interview'">🗣</span>
<span v-else-if="activity.type === 'saved'"></span>
<span v-else-if="activity.type === 'offer'">🎉</span>
</div>
<div class="activity-details">
<div class="activity-title">{{ activity.position }}</div>
<div class="activity-company">{{ activity.company }}</div>
<div class="activity-meta">
<span class="activity-date">{{ activity.date }}</span>
<span class="activity-status" :class="activity.type">{{ activity.status }}</span>
</div>
</div>
</div>
</div>
</div>
<!-- Upcoming Events -->
<div class="dashboard-card events-card">
<h3 class="card-title">Upcoming Events</h3>
<div class="events-list">
<div v-for="event in upcomingEvents" :key="event.id" class="event-item">
<div class="event-date">
<div class="event-day">{{ new Date(event.date).getDate() }}</div>
<div class="event-month">{{ new Date(event.date).toLocaleString('default', { month: 'short' }) }}</div>
</div>
<div class="event-details">
<div class="event-title">{{ event.title }}</div>
<div class="event-company">{{ event.company }}</div>
<div class="event-time">{{ event.time }}</div>
</div>
</div>
</div>
</div>
<!-- Recommended Jobs -->
<div class="dashboard-card recommended-card">
<h3 class="card-title">Recommended for You</h3>
<div class="recommended-list">
<div v-for="job in recommendedJobs" :key="job.id" class="recommended-item">
<div class="match-score">{{ job.matchScore }}% Match</div>
<div class="job-details">
<div class="job-title">{{ job.title }}</div>
<div class="job-company">{{ job.company }}</div>
<div class="job-meta">
<span class="job-location">{{ job.location }}</span>
<span class="job-salary">{{ job.salary }}</span>
</div>
</div>
<button class="view-job-btn">View</button>
</div>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.dashboard {
width: 100%;
.dashboard-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
@media (max-width: 768px) {
grid-template-columns: 1fr;
}
}
.stats-container {
grid-column: 1 / -1;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
@media (max-width: 768px) {
grid-template-columns: repeat(2, 1fr);
}
}
.stat-card {
background-color: var(--card-bg, #fff);
border: 1px solid var(--card-border, #ddd);
border-radius: 8px;
padding: 1.5rem;
text-align: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
.stat-value {
font-size: 2.5rem;
font-weight: 700;
color: var(--primary-color);
margin-bottom: 0.5rem;
}
.stat-label {
font-size: 0.9rem;
color: var(--text-color);
opacity: 0.8;
}
}
.dashboard-card {
background-color: var(--card-bg, #fff);
border: 1px solid var(--card-border, #ddd);
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
.card-title {
margin-top: 0;
margin-bottom: 1rem;
font-size: 1.2rem;
font-weight: 600;
color: var(--text-color);
border-bottom: 1px solid var(--card-border, #ddd);
padding-bottom: 0.75rem;
}
}
.activity-card {
.activity-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.activity-item {
display: flex;
align-items: flex-start;
padding-bottom: 1rem;
border-bottom: 1px solid var(--card-border, #eee);
&:last-child {
border-bottom: none;
padding-bottom: 0;
}
}
.activity-icon {
width: 2.5rem;
height: 2.5rem;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 1rem;
background-color: rgba(0, 0, 0, 0.05);
&.application {
background-color: rgba(52, 152, 219, 0.1);
}
&.interview {
background-color: rgba(155, 89, 182, 0.1);
}
&.saved {
background-color: rgba(241, 196, 15, 0.1);
}
&.offer {
background-color: rgba(46, 204, 113, 0.1);
}
}
.activity-details {
flex: 1;
}
.activity-title {
font-weight: 600;
margin-bottom: 0.25rem;
}
.activity-company {
font-size: 0.9rem;
margin-bottom: 0.5rem;
opacity: 0.8;
}
.activity-meta {
display: flex;
justify-content: space-between;
font-size: 0.8rem;
}
.activity-status {
font-weight: 600;
&.application {
color: #3498db;
}
&.interview {
color: #9b59b6;
}
&.saved {
color: #f1c40f;
}
&.offer {
color: #2ecc71;
}
}
}
.events-card {
.events-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.event-item {
display: flex;
align-items: center;
padding-bottom: 1rem;
border-bottom: 1px solid var(--card-border, #eee);
&:last-child {
border-bottom: none;
padding-bottom: 0;
}
}
.event-date {
width: 3rem;
height: 3rem;
border-radius: 8px;
background-color: var(--primary-color);
color: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-right: 1rem;
.event-day {
font-size: 1.2rem;
font-weight: 700;
line-height: 1;
}
.event-month {
font-size: 0.8rem;
text-transform: uppercase;
}
}
.event-details {
flex: 1;
}
.event-title {
font-weight: 600;
margin-bottom: 0.25rem;
}
.event-company {
font-size: 0.9rem;
margin-bottom: 0.25rem;
opacity: 0.8;
}
.event-time {
font-size: 0.8rem;
opacity: 0.7;
}
}
.recommended-card {
.recommended-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.recommended-item {
display: flex;
align-items: center;
padding-bottom: 1rem;
border-bottom: 1px solid var(--card-border, #eee);
&:last-child {
border-bottom: none;
padding-bottom: 0;
}
}
.match-score {
background-color: rgba(46, 204, 113, 0.1);
color: #2ecc71;
font-size: 0.8rem;
font-weight: 600;
padding: 0.25rem 0.5rem;
border-radius: 4px;
margin-right: 1rem;
white-space: nowrap;
}
.job-details {
flex: 1;
}
.job-title {
font-weight: 600;
margin-bottom: 0.25rem;
}
.job-company {
font-size: 0.9rem;
margin-bottom: 0.25rem;
opacity: 0.8;
}
.job-meta {
display: flex;
gap: 1rem;
font-size: 0.8rem;
opacity: 0.7;
}
.view-job-btn {
background-color: transparent;
border: 1px solid var(--primary-color);
color: var(--primary-color);
padding: 0.4rem 0.75rem;
border-radius: 4px;
font-size: 0.8rem;
cursor: pointer;
transition: all 0.2s;
&:hover {
background-color: var(--primary-color);
color: white;
}
}
}
}
</style>