Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
dtd
/
civitas.ui
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit f491ae2a
authored
Apr 14, 2025
by
Samuel Taniel Mulyadi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add jadwal
1 parent
8a050591
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
188 additions
and
7 deletions
components/beranda/UserJadwal.vue
components/beranda/UserJadwal.vue
View file @
f491ae2
...
...
@@ -5,10 +5,23 @@ import { useKeycloakStore } from '@/@core/stores/keycloakStore'
const
keycloakStore
=
useKeycloakStore
()
const
schedule
=
ref
<
any
[]
>
([])
const
loading
=
ref
(
false
)
const
viewMode
=
ref
<
'vertical'
|
'horizontal'
>
(
'vertical'
)
// ← track the mode
const
daysOfWeek
=
[
'Senin'
,
'Selasa'
,
'Rabu'
,
'Kamis'
,
'Jumat'
]
const
startHour
=
7
const
endHour
=
21
const
currentTime
=
ref
(
new
Date
())
// Function to check if the current time is within a schedule item range
function
isCurrentScheduleItem
(
item
:
any
)
{
const
now
=
currentTime
.
value
const
startTime
=
parseTime
(
item
.
start
)
const
endTime
=
parseTime
(
item
.
end
)
const
currentMinutes
=
(
now
.
getHours
()
-
startHour
)
*
60
+
now
.
getMinutes
()
// Check if the current time is within the range (startTime < currentMinutes < endTime)
return
currentMinutes
>=
startTime
&&
currentMinutes
<=
endTime
}
async
function
getData
()
{
loading
.
value
=
true
...
...
@@ -40,6 +53,8 @@ async function getData() {
lecturer
:
Object
.
values
(
course
.
PENGAJAR
).
join
(
', '
),
// Join multiple lecturers if exist
room
:
jadwal
.
NM_RUANG
,
building
:
jadwal
.
NM_GED
,
tgl_mulai
:
jadwal
.
TGL_MULAI
,
tgl_selesai
:
jadwal
.
TGL_SELESAI
,
})),
)
}
...
...
@@ -53,6 +68,8 @@ async function getData() {
lecturer
:
item
.
NAMA_DOSEN
,
room
:
item
.
NM_RUANG
,
building
:
item
.
NM_GED
,
tgl_mulai
:
item
.
TGL_MULAI
,
tgl_selesai
:
item
.
TGL_SELESAI
,
}))
}
else
if
(
keycloakStore
.
civitas
===
'staf'
)
{
...
...
@@ -97,14 +114,60 @@ function calculateRowSpan(start: string, end: string) {
return
rowSpan
}
// Group schedule by day
function
getScheduleByDay
(
day
:
string
)
{
return
schedule
.
value
.
filter
(
item
=>
item
.
day
===
day
)
}
// Get alternating color classes
function
getColorClass
(
index
:
number
)
{
const
colors
=
[
'red'
,
'blue'
,
'green'
]
return
`schedule-color-
${
colors
[
index
%
3
]}
`
}
</
script
>
<
template
>
<VCard
title=
"Jadwal Kuliah"
class=
"timetable-card"
>
<VCard
class=
"timetable"
>
<VCard
class=
"timetable-card"
>
<template
#
title
>
<div
class=
"d-flex align-center"
>
<!-- Left: Title -->
<span
class=
"me-auto"
>
Jadwal Kuliah
</span>
<!-- Right: Date Range Box -->
<div
class=
"me-auto date-range-box"
>
<span
v-if=
"schedule.length > 0"
>
{{
schedule
[
0
].
tgl_mulai
}}
/
{{
schedule
[
0
].
tgl_selesai
}}
</span>
</div>
<!-- Right: Icons -->
<div
class=
"d-flex gap-2"
>
<VBtn
icon
variant=
"text"
:color=
"viewMode === 'vertical' ? 'primary' : 'default'"
@
click=
"viewMode = 'vertical'"
>
<VIcon
icon=
"ri-layout-vertical-line"
/>
</VBtn>
<VBtn
icon
variant=
"text"
:color=
"viewMode === 'horizontal' ? 'primary' : 'default'"
@
click=
"viewMode = 'horizontal'"
>
<VIcon
icon=
"ri-layout-horizontal-line"
/>
</VBtn>
</div>
</div>
</
template
>
<VCard
v-if=
"viewMode === 'vertical'"
class=
"timetable"
>
<!-- Header Row -->
<div
class=
"grid-header"
>
<div
class=
"time-label"
>
...
...
@@ -173,10 +236,86 @@ function calculateRowSpan(start: string, end: string) {
</div>
</div>
</VCard>
<VCard
v-else
class=
"timetable px-4 py-6"
>
<table
class=
"w-100 text-left table-schedule fixed-table"
>
<thead>
<tr>
<th
v-for=
"day in daysOfWeek"
:key=
"day"
class=
"px-2 py-2"
>
{{ day }}
</th>
</tr>
</thead>
<tbody>
<tr
v-for=
"rowIndex in 10"
:key=
"`row-${rowIndex}`"
>
<td
v-for=
"(day, dayIndex) in daysOfWeek"
:key=
"day + rowIndex"
class=
"align-top px-2 py-3"
>
<div
v-if=
"getScheduleByDay(day)[rowIndex - 1]"
class=
"schedule-box"
:class=
"[getColorClass(rowIndex - 1)]"
>
<div
class=
"course-header mb-1"
>
<span
class=
"text-sm font-medium d-flex align-center gap-1"
>
<i
class=
"ri-time-line"
/>
{{
getScheduleByDay(day)[rowIndex - 1].start
}} - {{
getScheduleByDay(day)[rowIndex - 1].end
}}
</span>
<span
class=
"text-xs"
>
{{ getScheduleByDay(day)[rowIndex - 1].room }}
</span>
</div>
<div
class=
"course-title font-semibold text-sm mb-1"
>
<span
v-if=
"getScheduleByDay(day)[rowIndex - 1].course.includes('-')"
style=
"text-decoration: underline;"
>
{{ getScheduleByDay(day)[rowIndex - 1].course.split(' - ')[0] }}
</span>
<span
class=
"text-sm"
>
{{
getScheduleByDay(day)[rowIndex - 1].course.includes('-')
? getScheduleByDay(day)[rowIndex - 1].course.split(' - ')[1]
: getScheduleByDay(day)[rowIndex - 1].course
}}
</span>
</div>
<div
class=
"text-xs"
>
{{ getScheduleByDay(day)[rowIndex - 1].building }}
</div>
</div>
</td>
</tr>
</tbody>
</table>
</VCard>
</VCard>
</template>
<
style
scoped
>
.date-range-box
{
display
:
inline-block
;
border-radius
:
5px
;
background-color
:
rgba
(
var
(
--v-global-theme-primary
),
0.1
);
font-size
:
14px
;
font-weight
:
bold
;
margin-inline-start
:
10px
;
padding-block
:
5px
;
padding-inline
:
10px
;
}
.timetable
{
display
:
flex
;
flex-direction
:
column
;
...
...
@@ -219,6 +358,7 @@ function calculateRowSpan(start: string, end: string) {
.course-prefix
{
color
:
color-mix
(
in
srgb
,
rgba
(
var
(
--v-global-theme-primary
))
70%
,
black
30%
);
text-decoration
:
underline
;
}
.grid-body
{
...
...
@@ -248,13 +388,14 @@ function calculateRowSpan(start: string, end: string) {
.schedule-item
{
display
:
flex
;
overflow
:
hidden
;
flex-direction
:
column
;
align-items
:
flex-start
;
/* Keeps text left-aligned */
justify-content
:
flex-start
;
/* Aligns content to the top */
padding
:
4
px
;
padding
:
6
px
;
border-radius
:
6px
;
margin
:
2px
;
background-color
:
color-mix
(
in
srgb
,
rgba
(
var
(
--v-global-theme-primary
))
70%
,
white
3
0%
);
background-color
:
color-mix
(
in
srgb
,
rgba
(
var
(
--v-global-theme-primary
))
80%
,
white
2
0%
);
color
:
white
;
font-size
:
12px
;
outline
:
1px
solid
rgba
(
var
(
--v-border-color
),
var
(
--v-border-opacity
));
...
...
@@ -297,6 +438,46 @@ function calculateRowSpan(start: string, end: string) {
text-align
:
start
;
/* Aligns room to the right */
}
.fixed-table
{
border-collapse
:
collapse
;
inline-size
:
100%
;
table-layout
:
fixed
;
}
.fixed-table
thead
th
{
background-color
:
rgba
(
var
(
--v-global-theme-primary
));
color
:
white
;
font-weight
:
bold
;
text-align
:
center
;
}
.fixed-table
th
,
.fixed-table
td
{
padding
:
0
;
margin
:
0
;
}
.schedule-box
{
padding
:
6px
;
border-radius
:
8px
;
color
:
white
;
font-size
:
0.85rem
;
min-block-size
:
90px
;
}
/* Color themes for items */
.schedule-color-red
{
background-color
:
#6aa1fa
;
}
.schedule-color-blue
{
background-color
:
#46c298
;
}
.schedule-color-green
{
background-color
:
#eda36b
;
}
@media
screen
and
(
max-width
:
1200px
)
{
.course-title
{
border-block-end
:
0
solid
;
...
...
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment