Add streaks, scheduled releases, and notification settings

- Couple streaks with milestone notifications
- Scheduled pack releases with admin UI
- Notification preferences screen
- Refactored profile settings screens
- Partner activity notifications
This commit is contained in:
jjbrunton committed 2026-01-17 16:38:47 +00:00
1 parent 12f312421b
commit 494ed17fe2
82 files changed
+4189 -725

No files matched your search

@@ -13,7 +13,6 @@ CREATE TYPE dare_status AS ENUM (
'declined', -- Recipient declined
'cancelled' -- Sender cancelled before completion
);
-- ============================================================================
-- TABLES
-- ============================================================================
@@ -34,17 +33,14 @@ CREATE TABLE dare_packs (
avg_intensity NUMERIC(3,2),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
COMMENT ON TABLE dare_packs IS 'Collections of dares organized by theme or intensity level';
COMMENT ON COLUMN dare_packs.min_intensity IS 'Auto-calculated minimum intensity from dares in this pack';
COMMENT ON COLUMN dare_packs.max_intensity IS 'Auto-calculated maximum intensity from dares in this pack';
COMMENT ON COLUMN dare_packs.avg_intensity IS 'Auto-calculated average intensity from dares in this pack';
-- Create indexes for dare_packs
CREATE INDEX idx_dare_packs_sort_order ON dare_packs(sort_order);
CREATE INDEX idx_dare_packs_visibility ON dare_packs(is_public, is_premium);
CREATE INDEX idx_dare_packs_category ON dare_packs(category_id);
-- Dares table (individual dare content)
CREATE TABLE dares (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
@@ -54,15 +50,12 @@ CREATE TABLE dares (
suggested_duration_hours INTEGER,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
COMMENT ON TABLE dares IS 'Individual dares within dare packs';
COMMENT ON COLUMN dares.intensity IS 'Difficulty/spiciness level from 1 (mild) to 5 (intense)';
COMMENT ON COLUMN dares.suggested_duration_hours IS 'Suggested time to complete the dare in hours (null = no suggestion)';
-- Create indexes for dares
CREATE INDEX idx_dares_pack_id ON dares(pack_id);
CREATE INDEX idx_dares_intensity ON dares(intensity);
-- Sent dares table (tracks dare instances between partners)
CREATE TABLE sent_dares (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
@@ -81,21 +74,18 @@ CREATE TABLE sent_dares (
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
CONSTRAINT dare_or_custom CHECK (dare_id IS NOT NULL OR custom_dare_text IS NOT NULL)
);
COMMENT ON TABLE sent_dares IS 'Dare instances sent between partners in a couple';
COMMENT ON COLUMN sent_dares.dare_id IS 'Reference to the dare from a pack (null for custom dares)';
COMMENT ON COLUMN sent_dares.custom_dare_text IS 'Text for custom dares created by premium users';
COMMENT ON COLUMN sent_dares.custom_dare_intensity IS 'Intensity for custom dares (1-5)';
COMMENT ON COLUMN sent_dares.expires_at IS 'Deadline for completing the dare (null = no time limit)';
COMMENT ON COLUMN sent_dares.sender_notes IS 'Optional message from sender when sending the dare';
-- Create indexes for sent_dares
CREATE INDEX idx_sent_dares_couple_id ON sent_dares(couple_id);
CREATE INDEX idx_sent_dares_sender_id ON sent_dares(sender_id);
CREATE INDEX idx_sent_dares_recipient_id ON sent_dares(recipient_id);
CREATE INDEX idx_sent_dares_status ON sent_dares(status);
CREATE INDEX idx_sent_dares_expires_at ON sent_dares(expires_at) WHERE expires_at IS NOT NULL AND status = 'active';
-- Dare messages table (chat for each dare)
CREATE TABLE dare_messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
@@ -105,13 +95,10 @@ CREATE TABLE dare_messages (
read_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
COMMENT ON TABLE dare_messages IS 'Chat messages associated with each sent dare';
-- Create indexes for dare_messages
CREATE INDEX idx_dare_messages_sent_dare_id ON dare_messages(sent_dare_id);
CREATE INDEX idx_dare_messages_created_at ON dare_messages(sent_dare_id, created_at);
-- ============================================================================
-- TRIGGERS
-- ============================================================================
@@ -136,12 +123,10 @@ BEGIN
RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;
-- Create trigger on dares table
CREATE TRIGGER dare_intensity_stats_trigger
AFTER INSERT OR UPDATE OR DELETE ON dares
FOR EACH ROW EXECUTE FUNCTION update_dare_pack_intensity_stats();
-- ============================================================================
-- STATS FUNCTIONS
-- ============================================================================
@@ -163,7 +148,6 @@ BEGIN
(SELECT COUNT(*) FROM sent_dares WHERE recipient_id = p_user_id AND status = 'completed')::BIGINT;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Function to get dare stats for a couple
CREATE OR REPLACE FUNCTION get_couple_dare_stats(p_couple_id UUID)
RETURNS TABLE (
@@ -179,7 +163,6 @@ BEGIN
(SELECT COUNT(*) FROM sent_dares WHERE couple_id = p_couple_id AND status = 'active')::BIGINT;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- ============================================================================
-- ROW LEVEL SECURITY
-- ============================================================================
@@ -189,7 +172,6 @@ ALTER TABLE dare_packs ENABLE ROW LEVEL SECURITY;
ALTER TABLE dares ENABLE ROW LEVEL SECURITY;
ALTER TABLE sent_dares ENABLE ROW LEVEL SECURITY;
ALTER TABLE dare_messages ENABLE ROW LEVEL SECURITY;
-- -------------------------
-- dare_packs policies
-- -------------------------
@@ -198,7 +180,6 @@ ALTER TABLE dare_messages ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Public dare packs are viewable by everyone"
ON dare_packs FOR SELECT
USING (is_public = true);
-- Admins can view all dare packs
CREATE POLICY "Admins can view all dare packs"
ON dare_packs FOR SELECT
@@ -207,7 +188,6 @@ USING (
SELECT 1 FROM admin_users WHERE user_id = auth.uid()
)
);
-- Admins can insert dare packs
CREATE POLICY "Admins can insert dare packs"
ON dare_packs FOR INSERT
@@ -216,7 +196,6 @@ WITH CHECK (
SELECT 1 FROM admin_users WHERE user_id = auth.uid()
)
);
-- Admins can update dare packs
CREATE POLICY "Admins can update dare packs"
ON dare_packs FOR UPDATE
@@ -225,7 +204,6 @@ USING (
SELECT 1 FROM admin_users WHERE user_id = auth.uid()
)
);
-- Admins can delete dare packs
CREATE POLICY "Admins can delete dare packs"
ON dare_packs FOR DELETE
@@ -234,7 +212,6 @@ USING (
SELECT 1 FROM admin_users WHERE user_id = auth.uid()
)
);
-- -------------------------
-- dares policies
-- -------------------------
@@ -253,7 +230,6 @@ USING (
)
)
);
-- Admins can view all dares
CREATE POLICY "Admins can view all dares"
ON dares FOR SELECT
@@ -262,7 +238,6 @@ USING (
SELECT 1 FROM admin_users WHERE user_id = auth.uid()
)
);
-- Admins can insert dares
CREATE POLICY "Admins can insert dares"
ON dares FOR INSERT
@@ -271,7 +246,6 @@ WITH CHECK (
SELECT 1 FROM admin_users WHERE user_id = auth.uid()
)
);
-- Admins can update dares
CREATE POLICY "Admins can update dares"
ON dares FOR UPDATE
@@ -280,7 +254,6 @@ USING (
SELECT 1 FROM admin_users WHERE user_id = auth.uid()
)
);
-- Admins can delete dares
CREATE POLICY "Admins can delete dares"
ON dares FOR DELETE
@@ -289,7 +262,6 @@ USING (
SELECT 1 FROM admin_users WHERE user_id = auth.uid()
)
);
-- -------------------------
-- sent_dares policies
-- -------------------------
@@ -298,7 +270,6 @@ USING (
CREATE POLICY "Users can view their couple's sent dares"
ON sent_dares FOR SELECT
USING (couple_id = get_auth_user_couple_id());
-- Users can insert sent dares (sender must be the authenticated user)
CREATE POLICY "Users can send dares to their partner"
ON sent_dares FOR INSERT
@@ -306,12 +277,10 @@ WITH CHECK (
sender_id = auth.uid()
AND couple_id = get_auth_user_couple_id()
);
-- Users can update sent dares in their couple
CREATE POLICY "Users can update their couple's sent dares"
ON sent_dares FOR UPDATE
USING (couple_id = get_auth_user_couple_id());
-- Admins can view all sent dares
CREATE POLICY "Admins can view all sent dares"
ON sent_dares FOR SELECT
@@ -320,7 +289,6 @@ USING (
SELECT 1 FROM admin_users WHERE user_id = auth.uid()
)
);
-- -------------------------
-- dare_messages policies
-- -------------------------
@@ -335,7 +303,6 @@ USING (
AND sd.couple_id = get_auth_user_couple_id()
)
);
-- Users can insert messages for their couple's dares
CREATE POLICY "Users can send messages for their dares"
ON dare_messages FOR INSERT
@@ -347,7 +314,6 @@ WITH CHECK (
AND sd.couple_id = get_auth_user_couple_id()
)
);
-- Users can update messages in their dares (for read_at)
CREATE POLICY "Users can update message read status"
ON dare_messages FOR UPDATE
@@ -358,7 +324,6 @@ USING (
AND sd.couple_id = get_auth_user_couple_id()
)
);
-- Admins can view all dare messages
CREATE POLICY "Admins can view all dare messages"
ON dare_messages FOR SELECT
@@ -367,7 +332,6 @@ USING (
SELECT 1 FROM admin_users WHERE user_id = auth.uid()
)
);
-- ============================================================================
-- REALTIME
-- ============================================================================