sky: store birth_tz, prefill form from User model, drop localStorage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-04-21 21:54:34 -04:00
parent b5a92ddf77
commit 5c05bd6552
4 changed files with 41 additions and 45 deletions

View File

@@ -303,9 +303,12 @@ def sky_view(request):
return render(request, "apps/dashboard/sky.html", {
"preview_url": request.build_absolute_uri("/dashboard/sky/preview"),
"save_url": request.build_absolute_uri("/dashboard/sky/save"),
"saved_sky": request.user.sky_chart_data,
"saved_sky": request.user.sky_chart_data,
"saved_birth_dt": request.user.sky_birth_dt,
"saved_birth_place": request.user.sky_birth_place,
"saved_birth_lat": request.user.sky_birth_lat,
"saved_birth_lon": request.user.sky_birth_lon,
"saved_birth_tz": request.user.sky_birth_tz,
"page_class": "page-sky",
})
@@ -338,12 +341,13 @@ def sky_save(request):
user.sky_birth_lat = body.get('birth_lat')
user.sky_birth_lon = body.get('birth_lon')
user.sky_birth_place = body.get('birth_place', '')
user.sky_birth_tz = body.get('birth_tz', '')
user.sky_house_system = body.get('house_system', 'O')
user.sky_chart_data = body.get('chart_data')
user.save(update_fields=[
'sky_birth_dt', 'sky_birth_lat', 'sky_birth_lon',
'sky_birth_place', 'sky_house_system', 'sky_chart_data',
'sky_birth_place', 'sky_birth_tz', 'sky_house_system', 'sky_chart_data',
])
return JsonResponse({"saved": True})

View File

@@ -0,0 +1,18 @@
# Generated by Django 6.0 on 2026-04-22 01:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lyric', '0018_user_sky_fields'),
]
operations = [
migrations.AddField(
model_name='user',
name='sky_birth_tz',
field=models.CharField(blank=True, max_length=64),
),
]

View File

@@ -52,6 +52,7 @@ class User(AbstractBaseUser):
sky_birth_lat = models.DecimalField(max_digits=9, decimal_places=4, null=True, blank=True)
sky_birth_lon = models.DecimalField(max_digits=9, decimal_places=4, null=True, blank=True)
sky_birth_place = models.CharField(max_length=255, blank=True)
sky_birth_tz = models.CharField(max_length=64, blank=True)
sky_house_system = models.CharField(max_length=1, blank=True, default="O")
sky_chart_data = models.JSONField(null=True, blank=True)

View File

@@ -19,12 +19,14 @@
<div class="natus-field">
<label for="id_nf_date">Birth date</label>
<input id="id_nf_date" name="date" type="date" required>
<input id="id_nf_date" name="date" type="date" required
{% if saved_birth_dt %}value="{{ saved_birth_dt|date:'Y-m-d' }}"{% endif %}>
</div>
<div class="natus-field">
<label for="id_nf_time">Birth time</label>
<input id="id_nf_time" name="time" type="time" value="12:00">
<input id="id_nf_time" name="time" type="time"
value="{% if saved_birth_dt %}{{ saved_birth_dt|time:'H:i' }}{% else %}12:00{% endif %}">
<small>Local time at birth place. Use 12:00 if unknown.</small>
</div>
@@ -33,7 +35,8 @@
<div class="natus-place-wrap">
<input id="id_nf_place" name="place" type="text"
placeholder="Start typing a city…"
autocomplete="off">
autocomplete="off"
{% if saved_birth_place %}value="{{ saved_birth_place }}"{% endif %}>
<button type="button" id="id_nf_geolocate"
class="btn btn-secondary btn-sm"
title="Use device location">
@@ -47,19 +50,22 @@
<div>
<label>Latitude</label>
<input id="id_nf_lat" name="lat" type="text"
placeholder="—" readonly tabindex="-1">
placeholder="—" readonly tabindex="-1"
{% if saved_birth_lat %}value="{{ saved_birth_lat }}"{% endif %}>
</div>
<div>
<label>Longitude</label>
<input id="id_nf_lon" name="lon" type="text"
placeholder="—" readonly tabindex="-1">
placeholder="—" readonly tabindex="-1"
{% if saved_birth_lon %}value="{{ saved_birth_lon }}"{% endif %}>
</div>
</div>
<div class="natus-field">
<label for="id_nf_tz">Timezone</label>
<input id="id_nf_tz" name="tz" type="text"
placeholder="auto-detected from location">
placeholder="auto-detected from location"
{% if saved_birth_tz %}value="{{ saved_birth_tz }}"{% endif %}>
<small id="id_nf_tz_hint"></small>
</div>
@@ -109,9 +115,6 @@
const NOMINATIM = 'https://nominatim.openstreetmap.org/search';
const USER_AGENT = 'EarthmanRPG/1.0 (https://earthmanrpg.me)';
// localStorage key — fixed for the user's personal sky (not room-scoped)
const LS_KEY = 'natus-form:dashboard:sky';
let _lastChartData = null;
let _placeDebounce = null;
let _chartDebounce = null;
@@ -120,34 +123,6 @@
NatusWheel.preload();
// ── localStorage persistence ────────────────────────────────────────────
function _saveForm() {
const data = {
date: document.getElementById('id_nf_date').value,
time: document.getElementById('id_nf_time').value,
place: placeInput.value,
lat: latInput.value,
lon: lonInput.value,
tz: tzInput.value,
};
try { localStorage.setItem(LS_KEY, JSON.stringify(data)); } catch (_) {}
}
function _restoreForm() {
let data;
try { data = JSON.parse(localStorage.getItem(LS_KEY) || 'null'); } catch (_) {}
if (!data) return;
if (data.date) document.getElementById('id_nf_date').value = data.date;
if (data.time) document.getElementById('id_nf_time').value = data.time;
if (data.place) placeInput.value = data.place;
if (data.lat) latInput.value = data.lat;
if (data.lon) lonInput.value = data.lon;
if (data.tz) { tzInput.value = data.tz; tzHint.textContent = 'Auto-detected from coordinates.'; }
// If we have enough data from localStorage, kick off a wheel draw
if (_formReady()) schedulePreview();
}
// ── Status helper ───────────────────────────────────────────────────────
function setStatus(msg, type) {
@@ -209,7 +184,6 @@
latInput.value = parseFloat(place.lat).toFixed(4);
lonInput.value = parseFloat(place.lon).toFixed(4);
hideSuggestions();
_saveForm();
schedulePreview();
}
@@ -230,8 +204,7 @@
})
.then(r => r.json())
.then(data => { placeInput.value = _cityName(data.address) || data.display_name || ''; })
.catch(() => {})
.finally(() => _saveForm());
.catch(() => {});
setStatus('');
schedulePreview();
},
@@ -251,7 +224,6 @@
form.addEventListener('input', (e) => {
if (e.target === placeInput) return;
_saveForm();
clearTimeout(_chartDebounce);
_chartDebounce = setTimeout(schedulePreview, CHART_DELAY);
});
@@ -312,6 +284,7 @@
birth_lat: parseFloat(latInput.value),
birth_lon: parseFloat(lonInput.value),
birth_place: placeInput.value,
birth_tz: tzInput.value.trim(),
house_system: _lastChartData.house_system || 'O',
chart_data: _lastChartData,
};
@@ -340,9 +313,9 @@
return m ? m[1] : '';
}
// ── Restore persisted form on load ───────────────────────────────────────
// ── Auto-preview on load if form is pre-filled from saved sky ───────────
_restoreForm();
if (_formReady()) schedulePreview();
})();
</script>
{% endblock %}