forked from mirrors/pronouns.cc
feat: display timezone
This commit is contained in:
parent
309aa569f6
commit
e10db2fa09
6 changed files with 55 additions and 0 deletions
|
@ -52,6 +52,7 @@ type User struct {
|
|||
IsAdmin bool
|
||||
ListPrivate bool
|
||||
LastSIDReroll time.Time `db:"last_sid_reroll"`
|
||||
Timezone *string
|
||||
|
||||
DeletedAt *time.Time
|
||||
SelfDelete *bool
|
||||
|
@ -113,6 +114,21 @@ func (u User) NumProviders() (numProviders int) {
|
|||
return numProviders
|
||||
}
|
||||
|
||||
// UTCOffset returns the user's UTC offset in seconds. If the user does not have a timezone set, `ok` is false.
|
||||
func (u User) UTCOffset() (offset int, ok bool) {
|
||||
if u.Timezone == nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
loc, err := time.LoadLocation(*u.Timezone)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
_, offset = time.Now().In(loc).Zone()
|
||||
return offset, true
|
||||
}
|
||||
|
||||
type Badge int32
|
||||
|
||||
const (
|
||||
|
|
|
@ -28,12 +28,14 @@ type GetUserResponse struct {
|
|||
CustomPreferences db.CustomPreferences `json:"custom_preferences"`
|
||||
Flags []db.UserFlag `json:"flags"`
|
||||
Badges db.Badge `json:"badges"`
|
||||
UTCOffset *int `json:"utc_offset"`
|
||||
}
|
||||
|
||||
type GetMeResponse struct {
|
||||
GetUserResponse
|
||||
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Timezone *string `json:"timezone"`
|
||||
|
||||
MaxInvites int `json:"max_invites"`
|
||||
IsAdmin bool `json:"is_admin"`
|
||||
|
@ -87,6 +89,10 @@ func dbUserToResponse(u db.User, fields []db.Field, members []db.Member, flags [
|
|||
resp.Badges |= db.BadgeAdmin
|
||||
}
|
||||
|
||||
if offset, ok := u.UTCOffset(); ok {
|
||||
resp.UTCOffset = &offset
|
||||
}
|
||||
|
||||
resp.Members = make([]PartialMember, len(members))
|
||||
for i := range members {
|
||||
resp.Members[i] = PartialMember{
|
||||
|
@ -195,6 +201,7 @@ func (s *Server) getMeUser(w http.ResponseWriter, r *http.Request) error {
|
|||
render.JSON(w, r, GetMeResponse{
|
||||
GetUserResponse: dbUserToResponse(u, fields, members, flags),
|
||||
CreatedAt: u.ID.Time(),
|
||||
Timezone: u.Timezone,
|
||||
MaxInvites: u.MaxInvites,
|
||||
IsAdmin: u.IsAdmin,
|
||||
ListPrivate: u.ListPrivate,
|
||||
|
|
|
@ -311,6 +311,8 @@ func (s *Server) patchUser(w http.ResponseWriter, r *http.Request) error {
|
|||
// echo the updated user back on success
|
||||
render.JSON(w, r, GetMeResponse{
|
||||
GetUserResponse: dbUserToResponse(u, fields, nil, flags),
|
||||
CreatedAt: u.ID.Time(),
|
||||
Timezone: u.Timezone,
|
||||
MaxInvites: u.MaxInvites,
|
||||
IsAdmin: u.IsAdmin,
|
||||
ListPrivate: u.ListPrivate,
|
||||
|
|
|
@ -14,6 +14,7 @@ export interface User {
|
|||
links: string[];
|
||||
member_title: string | null;
|
||||
badges: number;
|
||||
utc_offset: number | null;
|
||||
|
||||
names: FieldEntry[];
|
||||
pronouns: Pronoun[];
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
Modal,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
Tooltip,
|
||||
} from "sveltestrap";
|
||||
import { DateTime, Duration, FixedOffsetZone, Zone } from "luxon";
|
||||
import FieldCard from "$lib/components/FieldCard.svelte";
|
||||
import PronounLink from "$lib/components/PronounLink.svelte";
|
||||
import PartialMemberCard from "$lib/components/PartialMemberCard.svelte";
|
||||
|
@ -77,6 +79,24 @@
|
|||
let memberNameValid = true;
|
||||
$: memberNameValid = memberNameRegex.test(newMemberName);
|
||||
|
||||
let currentTime: string | null;
|
||||
let timezone: string | null;
|
||||
$: setTime(data.utc_offset);
|
||||
|
||||
const setTime = (offset: number | null) => {
|
||||
if (!offset) {
|
||||
currentTime = null;
|
||||
timezone = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const now = DateTime.now();
|
||||
const zone = FixedOffsetZone.instance(offset / 60);
|
||||
|
||||
currentTime = now.setZone(zone).toLocaleString(DateTime.TIME_SIMPLE);
|
||||
timezone = zone.formatOffset(now.toUnixInteger(), "narrow");
|
||||
};
|
||||
|
||||
const createMember = async () => {
|
||||
try {
|
||||
const member = await apiFetchClient<Member>("/members", "POST", {
|
||||
|
@ -168,6 +188,10 @@
|
|||
{:else}
|
||||
<h2>@{data.name} <Badges userBadges={data.badges} /></h2>
|
||||
{/if}
|
||||
{#if data.utc_offset}
|
||||
<Tooltip target="user-clock" placement="top">Current time</Tooltip>
|
||||
<Icon id="user-clock" name="clock" aria-label="This user's current time" /> {currentTime} <span class="text-body-secondary">(UTC{timezone})</span>
|
||||
{/if}
|
||||
{#if profileEmpty && $userStore?.id === data.id}
|
||||
<hr />
|
||||
<p>
|
||||
|
|
5
scripts/migrate/019_timezones.sql
Normal file
5
scripts/migrate/019_timezones.sql
Normal file
|
@ -0,0 +1,5 @@
|
|||
-- +migrate Up
|
||||
|
||||
-- 2023-07-30: Add user timezones
|
||||
|
||||
alter table users add column timezone text null;
|
Loading…
Reference in a new issue