new
parent
d3df878d0e
commit
80c0ddb33d
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.5 on 2024-08-09 08:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('osichat', '0021_chatroomreview_details'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='visitorlog',
|
||||
name='title',
|
||||
field=models.CharField(blank=True, max_length=500, null=True),
|
||||
),
|
||||
]
|
@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.5 on 2024-08-09 09:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('osichat', '0022_visitorlog_title'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='visitor',
|
||||
name='browser_name',
|
||||
field=models.CharField(blank=True, max_length=100, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='visitor',
|
||||
name='os_name',
|
||||
field=models.CharField(blank=True, max_length=100, null=True),
|
||||
),
|
||||
]
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,24 @@
|
||||
{% load static %}
|
||||
<div data-visitorid = {{visitor.id}} class="visitor w-full flex justify-between gap-2 items-center py-3 px-3 border-b border-gray-200 text-sm cursor-pointer bg-white">
|
||||
<div class="w-full flex gap-2 items-center">
|
||||
<div class="w-[40px] h-[40px] bg-osiblue rounded-full relative">
|
||||
{% if not visitor.country == 'Unknown' %}
|
||||
<img src="{{visitor.flag_image_url}}">
|
||||
{% else %}
|
||||
<img class="w-[30px] h-[25px] absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" src="{% static 'images/ositcom_logos/ositcomwhite(o).png' %}">
|
||||
{% endif %}
|
||||
|
||||
{% if visitor.is_online %}
|
||||
<div class="online absolute w-[12px] h-[12px] border-2 border-white bg-green-600 rounded-full bottom-0 right-0"></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<p class="text-secondosiblue font-poppinsBold">{{visitor.ip_address}}</p>
|
||||
<p class="text-fifthosiblue text-xs">{{visitor.visitorlog_set.all.last.url}}</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<p class="duration text-gray-500 text-sm">{{visitor.total_duration}}</p>
|
||||
</div>
|
@ -1,30 +1,47 @@
|
||||
{% load static %}
|
||||
<!-- VISITORS -->
|
||||
<div class="h-full flex flex-col" id="visitors">
|
||||
<div class="h-full flex flex-col">
|
||||
<div class="w-full py-3 px-3 border-b border-gray-200 flex items-center gap-2">
|
||||
<div class="w-[20px] h-[20px] bg-green-600 rounded-full onlineDot">
|
||||
<div class="wave"></div>
|
||||
</div>
|
||||
|
||||
<p class="text-secondosiblue">Active</p>
|
||||
<p class="text-secondosiblue">Visitors today</p>
|
||||
</div>
|
||||
|
||||
{% for visitor in visitors %}
|
||||
<div class="w-full flex justify-between gap-2 items-center py-3 px-3 border-b border-gray-200 text-sm cursor-pointer bg-white">
|
||||
<div class="w-full flex gap-2 items-center">
|
||||
<div class="w-[40px] h-[40px] rounded-full">
|
||||
<img src="{{visitor.flag_image_url}}">
|
||||
</div>
|
||||
<div id="visitors">
|
||||
{% for visitor in visitors %}
|
||||
<div data-visitorid = {{visitor.id}} class="visitor w-full flex justify-between gap-2 items-center py-3 px-3 border-b border-gray-200 text-sm cursor-pointer bg-white">
|
||||
<div class="w-full flex gap-2 items-center">
|
||||
<div class="w-[40px] h-[40px] bg-osiblue rounded-full relative">
|
||||
{% if not visitor.country == 'Unknown' %}
|
||||
<img src="{{visitor.flag_image_url}}">
|
||||
{% else %}
|
||||
<img class="w-[30px] h-[25px] absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" src="{% static 'images/ositcom_logos/ositcomwhite(o).png' %}">
|
||||
{% endif %}
|
||||
|
||||
{% if visitor.is_online %}
|
||||
<div class="online absolute w-[12px] h-[12px] border-2 border-white bg-green-600 rounded-full bottom-0 right-0"></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<p class="text-secondosiblue font-poppinsBold">{{visitor.ip_address}}</p>
|
||||
<p class="text-fifthosiblue text-xs">{{visitor.visitorlog_set.all.last.url}}</p>
|
||||
<div class="flex flex-col">
|
||||
<p class="text-secondosiblue font-poppinsBold">{{visitor.ip_address}}</p>
|
||||
<p class="text-fifthosiblue text-xs">
|
||||
{% if not visitor.visitorlog_set.all.last.title %}
|
||||
{{ visitor.visitorlog_set.all.last.url|slice:":26" }}{% if visitor.visitorlog_set.all.last.url|length > 26 %}…{% endif %}
|
||||
{% else %}
|
||||
{{ visitor.visitorlog_set.all.last.title|slice:":26" }}{% if visitor.visitorlog_set.all.last.title|length > 26 %}…{% endif %}
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<p class="text-gray-500 text-sm">00:00</p>
|
||||
<p class="duration text-gray-500 text-sm">{{visitor.total_duration}}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
||||
<audio id="visitor-notification-sound" src="{{domain}}/static/notifications/new-visitor.mp3" preload="auto"></audio>
|
@ -0,0 +1,27 @@
|
||||
function updateOnlineDurations() {
|
||||
document.querySelectorAll('.visitor').forEach(visitorDiv => {
|
||||
if (visitorDiv.querySelector('.online')) {
|
||||
const durationElem = visitorDiv.querySelector('.duration');
|
||||
const currentText = durationElem.textContent;
|
||||
const [hours, minutes, seconds] = currentText.split(':').map(Number);
|
||||
const totalSeconds = hours * 3600 + minutes * 60 + seconds;
|
||||
|
||||
// Increment the duration by 1 second
|
||||
const updatedTotalSeconds = totalSeconds + 1;
|
||||
const updatedHours = Math.floor(updatedTotalSeconds / 3600);
|
||||
const updatedMinutes = Math.floor((updatedTotalSeconds % 3600) / 60);
|
||||
const updatedSeconds = updatedTotalSeconds % 60;
|
||||
|
||||
// Format the updated duration
|
||||
const formattedDuration =
|
||||
(updatedHours > 0 ? `${String(updatedHours).padStart(2, '0') + ':' : ''}` +
|
||||
`${String(updatedMinutes).padStart(2, '0')}:${String(updatedSeconds).padStart(2, '0')}`);
|
||||
|
||||
// Update the duration element
|
||||
durationElem.textContent = formattedDuration;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Call this function at intervals to update durations
|
||||
setInterval(updateOnlineDurations, 1000); // Update every second
|
Binary file not shown.
Loading…
Reference in New Issue