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 a26da8c6
authored
Mar 27, 2025
by
Samuel Taniel Mulyadi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add Parkir Status:
1 parent
777aabba
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
121 additions
and
8 deletions
components/beranda/UserJadwal.vue
views/dstipro/beranda/UserProfileHeader.vue
components/beranda/UserJadwal.vue
View file @
a26da8c
...
...
@@ -39,6 +39,7 @@ async function getData() {
course
:
course
.
NM_KLS_MK
,
lecturer
:
Object
.
values
(
course
.
PENGAJAR
).
join
(
', '
),
// Join multiple lecturers if exist
room
:
jadwal
.
NM_RUANG
,
building
:
jadwal
.
NM_GED
,
})),
)
}
...
...
@@ -51,6 +52,7 @@ async function getData() {
course
:
item
.
NM_KLS_MK
,
lecturer
:
item
.
NAMA_DOSEN
,
room
:
item
.
NM_RUANG
,
building
:
item
.
NM_GED
,
}))
}
else
if
(
keycloakStore
.
civitas
===
'staf'
)
{
...
...
@@ -102,7 +104,7 @@ function calculateRowSpan(start: string, end: string) {
title=
"Jadwal Kuliah"
class=
"timetable-card"
>
<
div
class=
"timetable"
>
<
VCard
class=
"timetable"
>
<!-- Header Row -->
<div
class=
"grid-header"
>
<div
class=
"time-label"
>
...
...
@@ -148,7 +150,9 @@ function calculateRowSpan(start: string, end: string) {
}"
>
<div
class=
"course-header"
>
<span
class=
"time"
>
{{
item
.
start
}}
-
{{
item
.
end
}}
</span>
<span
class=
"time"
>
<i
class=
"ri-time-line"
/>
{{
item
.
start
}}
-
{{
item
.
end
}}
</span>
<span
class=
"room"
>
{{
item
.
room
}}
</span>
</div>
<div
class=
"course-title"
>
...
...
@@ -162,11 +166,14 @@ function calculateRowSpan(start: string, end: string) {
{{
item
.
course
.
includes
(
'-'
)
?
item
.
course
.
split
(
' - '
)[
1
]
:
item
.
course
}}
</span>
</div>
<div
class=
"building"
>
{{
item
.
building
}}
</div>
</div>
</div>
</div>
</VCard>
</VCard>
</
template
>
<
style
scoped
>
...
...
@@ -174,8 +181,8 @@ function calculateRowSpan(start: string, end: string) {
display
:
flex
;
flex-direction
:
column
;
padding
:
0
!important
;
border-radius
:
12px
;
margin-block
:
0
;
margin-block-end
:
20px
;
margin-inline
:
20px
;
/* Only applies margin to left and right */
max-inline-size
:
calc
(
100%
-
40px
);
/* Adjusts width accordingly */
overflow-x
:
auto
;
...
...
@@ -187,6 +194,7 @@ function calculateRowSpan(start: string, end: string) {
color
:
white
;
font-weight
:
bold
;
grid-template-columns
:
80px
repeat
(
5
,
1
fr
);
padding-inline
:
5px
;
text-align
:
center
;
}
...
...
@@ -200,9 +208,13 @@ function calculateRowSpan(start: string, end: string) {
.course-title
{
display
:
flex
;
flex-wrap
:
wrap
;
border-block-end
:
1px
solid
;
font-size
:
12px
;
font-weight
:
bold
;
gap
:
4px
;
inline-size
:
100%
;
/* Ensures the border spans the entire container */
margin-block-end
:
5px
;
padding-block-end
:
5px
;
}
.course-prefix
{
...
...
@@ -213,6 +225,7 @@ function calculateRowSpan(start: string, end: string) {
display
:
grid
;
grid-template-columns
:
80px
auto
;
/* Time column + Schedule grid */
padding-block
:
30px
;
padding-inline
:
5px
;
}
.time-column
{
...
...
@@ -244,6 +257,7 @@ function calculateRowSpan(start: string, end: string) {
background-color
:
color-mix
(
in
srgb
,
rgba
(
var
(
--v-global-theme-primary
))
70%
,
white
30%
);
color
:
white
;
font-size
:
12px
;
outline
:
1px
solid
rgba
(
var
(
--v-border-color
),
var
(
--v-border-opacity
));
text-align
:
start
;
/* Ensures text is left-aligned */
}
...
...
@@ -272,4 +286,10 @@ function calculateRowSpan(start: string, end: string) {
font-weight
:
normal
;
text-align
:
end
;
/* Aligns room to the right */
}
.building
{
font-weight
:
normal
;
opacity
:
0.8
;
text-align
:
end
;
/* Aligns room to the right */
}
</
style
>
views/dstipro/beranda/UserProfileHeader.vue
View file @
a26da8c
...
...
@@ -37,26 +37,38 @@ const items = ref<Record<string, any>>({})
const
loading
=
ref
(
false
)
const
errordata
=
ref
(
''
)
const
isBirthday
=
ref
(
false
)
const
parkirItems
=
ref
(
null
)
async
function
getData
()
{
loading
.
value
=
true
errordata
.
value
=
''
try
{
const
apiEndpoint
=
'https://api.ui.ac.id/me'
const
apiEndpoints
=
[
'https://api.ui.ac.id/me'
,
'https://api.ui.ac.id/my/parkir/aktif'
,
]
const
response
=
await
fetch
(
apiEndpoint
,
{
const
responses
=
await
Promise
.
all
(
apiEndpoints
.
map
(
endpoint
=>
fetch
(
endpoint
,
{
headers
:
{
Authorization
:
`Bearer
${
keycloakStore
.
accessToken
}
`
,
},
})
}),
))
for
(
const
response
of
responses
)
{
if
(
!
response
.
ok
)
throw
new
Error
(
'Gagal mengambil data'
)
const
dataku
=
await
response
.
json
()
}
const
[
dataku
,
parkirData
]
=
await
Promise
.
all
(
responses
.
map
(
res
=>
res
.
json
()))
items
.
value
=
dataku
// parkirItems.value = parkirData.data || {} // Store parkir data separately
parkirItems
.
value
=
parkirData
.
data
&&
Object
.
keys
(
parkirData
.
data
).
length
?
parkirData
.
data
:
null
}
catch
(
err
:
any
)
{
catch
(
err
)
{
errordata
.
value
=
err
.
message
||
'Terjadi kesalahan saat mengambil data'
}
finally
{
...
...
@@ -64,6 +76,32 @@ async function getData() {
}
}
const
daysLeft
=
computed
(()
=>
{
if
(
!
parkirItems
.
value
)
return
0
const
endDate
=
new
Date
(
parkirItems
.
value
.
date_end_service
)
const
now
=
new
Date
()
return
Math
.
max
(
0
,
Math
.
ceil
((
endDate
-
now
)
/
(
1000
*
60
*
60
*
24
)))
})
const
parkirStatus
=
computed
(()
=>
{
return
daysLeft
.
value
>
0
?
'Parkir Aktif'
:
'Parkir Non Aktif'
})
const
progress
=
computed
(()
=>
{
if
(
!
parkirItems
.
value
)
return
0
const
endDate
=
new
Date
(
parkirItems
.
value
.
date_end_service
)
const
startDate
=
new
Date
(
parkirItems
.
value
.
date_start_service
)
const
now
=
new
Date
()
// Reverse the calculation: 100% when starting, 0% when ending
return
Math
.
max
(
0
,
Math
.
min
(
100
,
((
endDate
-
now
)
/
(
endDate
-
startDate
))
*
100
))
})
// Fetch data from API
onMounted
(()
=>
{
getData
()
...
...
@@ -141,6 +179,10 @@ const ulangTahunBerikutnya = computed(() => {
return
`
${
diff
.
months
()}
bulan,
${
diff
.
days
()}
hari`
})
const
goToParking
=
()
=>
{
window
.
open
(
'https://parkir.ui.ac.id/apps/site/index'
,
'_blank'
)
}
</
script
>
<
template
>
...
...
@@ -197,6 +239,57 @@ const ulangTahunBerikutnya = computed(() => {
</div>
<div
v-if=
"parkirItems"
class=
"d-flex align-center gap-x-2"
>
<VIcon
size=
"24"
icon=
"ri-car-line"
/>
<VBtn
variant=
"tonal"
:color=
"daysLeft > 0 ? 'primary' : 'error'"
@
click=
"goToParking"
>
{{
parkirStatus
}}
<VTooltip
activator=
"parent"
location=
"top"
>
<div
class=
"d-flex flex-column p-2"
>
<div
class=
"d-flex align-center gap-x-2"
>
<VIcon
size=
"20"
icon=
"ri-calendar-line"
/>
<span>
Mulai:
{{
parkirItems
.
date_start_service
}}
</span>
</div>
<div
class=
"d-flex align-center gap-x-2"
>
<VIcon
size=
"20"
icon=
"ri-calendar-check-line"
/>
<span>
Berakhir:
{{
parkirItems
.
date_end_service
}}
</span>
</div>
<div
class=
"d-flex align-center gap-x-2"
>
<VIcon
size=
"20"
icon=
"ri-time-line"
/>
<span>
{{
daysLeft
}}
hari tersisa
</span>
</div>
<VProgressLinear
:model-value=
"progress"
color=
"primary"
height=
"6"
rounded
/>
</div>
</VTooltip>
</VBtn>
</div>
<div
v-if=
"!isBirthday"
class=
"d-flex align-center gap-x-2"
>
...
...
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