From 0516a7fa12fcd90ca36d9f0014944f2824407730 Mon Sep 17 00:00:00 2001
From: Pushp
Date: Tue, 27 Oct 2026 19:06:50 +0530
Subject: [PATCH 1/3] feat(profile): optional birth time, time zone and
birthplace; privacy policy for birth details
- Birthplace search (GET /profile/places) fills coordinates and time zone; birth time with a
time zone; at onboarding (optional) and editable any time in the profile (date stays locked)
- Privacy policy: what date of birth and birth details are used for, visibility, retention,
Amazon Location Service, correction, consent
---
src/components/legal/Privacy.tsx | 55 +++-
.../onboarding/BirthTimePlaceFields.tsx | 256 ++++++++++++++++++
.../onboarding/OnboardingWizard.tsx | 13 +-
src/features/profile/ProfileView.tsx | 24 +-
src/tests/birth-time-place.test.ts | 27 ++
5 files changed, 369 insertions(+), 6 deletions(-)
create mode 100644 src/components/onboarding/BirthTimePlaceFields.tsx
create mode 100644 src/tests/birth-time-place.test.ts
diff --git a/src/components/legal/Privacy.tsx b/src/components/legal/Privacy.tsx
index dbe7182..b318244 100644
--- a/src/components/legal/Privacy.tsx
+++ b/src/components/legal/Privacy.tsx
@@ -80,7 +80,11 @@ export function Privacy() {
Account Information
Email address
-
Name and date of birth
+
Name and date of birth (required; your age is calculated from it and is never stored separately)
Profile photos, videos, and audio (encrypted storage)
Profile details, bio, and interests
@@ -136,6 +140,40 @@ export function Privacy() {
available for non-critical)
+
+
✓ Date of Birth and Traditional Compatibility
+
+
+ Date of birth. You give it once, at sign-up. We use it to show your age
+ (calculated fresh every time, never stored as a separate number), to keep OneHook adults-only
+ (18+), and for age preferences in matching. Other members see your age, never your date of
+ birth. You cannot change it yourself; if it is wrong, our support team can correct it after
+ checking proof such as a government ID, at most twice per account, and each correction is
+ recorded with the reason.
+
+
+ Birth time, time zone and birthplace (optional). If you add them, together
+ with your date of birth they are used for one purpose: estimating traditional compatibility
+ between members (for example Kundali, Western natal charts, Bazi and Tzolk'in). The
+ result slightly changes the order in which profiles are suggested to you and to others; it
+ never hides anyone and is never shown as a score. You can add, change or remove them at any
+ time in your profile.
+
+
+ How it is handled. We store the coordinates of your birthplace rounded to
+ about 1 km, plus the place name you picked. Birth details are visible only to you. They are
+ not shared with other members, not sent to our AI recommendation service, and removed from our
+ analytics, which keep only your age at the time of an event. From these details we compute a
+ short coded summary (a few bytes) that is used only for matching. Birthplace search is
+ answered by Amazon Location Service; what you type is not stored.
+
+
+ By entering your date of birth you consent to these uses; by adding birth time or place you
+ consent to their use for traditional compatibility. You can withdraw that consent by removing
+ the optional details from your profile.
+
+
+
✗ We Do NOT Use Your Data For
@@ -577,6 +615,14 @@ export function Privacy() {
Data deleted within 30 days of account deletion (except where required by law)
+
+ Date of Birth and Birth Details:
+
+ Kept while your account is active and deleted with it, together with the matching summary
+ computed from them and any record of a support correction. Removing your birth time or place
+ deletes them and their summary straight away.
+
+
Video Applications:
@@ -626,7 +672,9 @@ export function Privacy() {
Right to Access: Request a copy of all your personal data we hold
- Right to Correction: Update or correct inaccurate information
+ Right to Correction: Update or correct inaccurate information. Your date of
+ birth is corrected by our support team on request, with proof (see{' '}
+ section 3)
Right to Deletion: Request permanent deletion of your account and
@@ -727,6 +775,9 @@ export function Privacy() {
SageMaker, hosted
in AWS (India region)
diff --git a/src/components/onboarding/BirthTimePlaceFields.tsx b/src/components/onboarding/BirthTimePlaceFields.tsx
new file mode 100644
index 0000000..603414e
--- /dev/null
+++ b/src/components/onboarding/BirthTimePlaceFields.tsx
@@ -0,0 +1,256 @@
+import { useEffect, useMemo, useRef, useState } from 'react';
+import { MapPin, Clock, X } from 'lucide-react';
+import { sdkClient } from '../../api/sdk-client';
+import { UiElement, trackProps } from '../../lib/analytics/analytics';
+
+/** The optional parts of birthDetails. Only the date is locked; these can change at any time. */
+export interface BirthTimePlace {
+ time?: string;
+ timeZone?: string;
+ latitude?: number;
+ longitude?: number;
+ placeName?: string;
+}
+
+interface Props {
+ value: BirthTimePlace;
+ onChange: (next: BirthTimePlace) => void;
+ /** Where the fields are shown: onboarding or the profile editor (telemetry id; never a value). */
+ surface?: 'onboarding' | 'profile';
+}
+
+const browserZone = (() => {
+ try {
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
+ } catch {
+ return 'UTC';
+ }
+})();
+
+const allZones: string[] = (() => {
+ try {
+ return (Intl as unknown as { supportedValuesOf(k: string): string[] }).supportedValuesOf(
+ 'timeZone'
+ );
+ } catch {
+ return [browserZone, 'UTC'];
+ }
+})();
+
+/**
+ * Optional birth time and birthplace. Picking a place fills its coordinates and time zone (from Amazon
+ * Location via GET /profile/places/{id}); without a place the member can still choose a time zone so a
+ * birth time is meaningful. Everything here only refines traditional compatibility, never age.
+ */
+export function BirthTimePlaceFields({ value, onChange, surface = 'onboarding' }: Props) {
+ // Birth details are personal data: telemetry records only that a choice was made, never what.
+ const element =
+ surface === 'profile'
+ ? UiElement.PROFILE_EDIT_CHOICE_SELECT
+ : UiElement.ONBOARDING_CHOICE_SELECT;
+ const [query, setQuery] = useState(value.placeName ?? '');
+ const [results, setResults] = useState<{ placeId: string; label: string }[]>([]);
+ const [searching, setSearching] = useState(false);
+ const [error, setError] = useState(null);
+ const seq = useRef(0);
+
+ useEffect(() => {
+ const q = query.trim();
+ if (q.length < 2 || q === value.placeName) {
+ setResults([]);
+ return;
+ }
+ const mine = ++seq.current;
+ const timer = setTimeout(async () => {
+ setSearching(true);
+ try {
+ const res = await sdkClient.searchPlaces({ q, lang: navigator.language?.slice(0, 2) });
+ if (mine === seq.current)
+ setResults((res.places ?? []).map((p) => ({ placeId: p.placeId!, label: p.label! })));
+ setError(null);
+ } catch {
+ if (mine === seq.current) setError('Place search is unavailable right now.');
+ } finally {
+ if (mine === seq.current) setSearching(false);
+ }
+ }, 300);
+ return () => clearTimeout(timer);
+ }, [query, value.placeName]);
+
+ const choose = async (placeId: string) => {
+ setResults([]);
+ try {
+ const p = await sdkClient.getPlace({ placeId });
+ setQuery(p.label!);
+ onChange({
+ ...value,
+ placeName: p.label,
+ latitude: p.latitude,
+ longitude: p.longitude,
+ timeZone: p.timeZone ?? value.timeZone,
+ });
+ } catch {
+ setError('Could not load that place. Please pick it again.');
+ }
+ };
+
+ const clearPlace = () => {
+ setQuery('');
+ onChange({ ...value, placeName: undefined, latitude: undefined, longitude: undefined });
+ };
+
+ const zones = useMemo(() => allZones, []);
+ const zone = value.timeZone ?? (value.time ? browserZone : undefined);
+
+ return (
+
+
+ Optional. Your birth time and place only refine traditional compatibility (Kundali, natal
+ chart, Bazi and more). They are never shown to other members, and you can add or change them
+ at any time.
+