a a vibe-coded abomination experiment of a fragrance review platform built on the atmosphere.
drydown.social
1import { calculateElapsedHours } from './reviewUtils'
2
3export interface EditValidationResult {
4 canEditStage1: boolean
5 canEditStage2: boolean
6 canEditStage3: boolean
7 canAddStage2: boolean
8 canAddStage3: boolean
9 canEditText: boolean
10 canChangeFragrance: boolean
11 error?: string
12}
13
14/**
15 * Determines what stages can be edited based on review state and elapsed time
16 */
17export function validateEditPermissions(review: any): EditValidationResult {
18 const elapsed = calculateElapsedHours(review.createdAt)
19
20 // Text and fragrance can ALWAYS be edited
21 const canEditText = true
22 const canChangeFragrance = true
23
24 // After 24 hours, ratings/stages cannot be edited
25 if (elapsed >= 24) {
26 return {
27 canEditStage1: false,
28 canEditStage2: false,
29 canEditStage3: false,
30 canAddStage2: false,
31 canAddStage3: false,
32 canEditText,
33 canChangeFragrance,
34 error: 'Stage ratings cannot be edited after 24 hours'
35 }
36 }
37
38 const hasStage1 = !!(review.openingRating && review.openingProjection)
39 const hasStage2 = !!(review.drydownRating && review.midProjection && review.sillage)
40 const hasStage3 = !!(review.endRating && review.complexity && review.longevity && review.overallRating)
41
42 // Stage 1 can always be edited within 24 hours
43 const canEditStage1 = hasStage1
44
45 // Stage 2 can be edited if it exists, or added after 1.5 hours
46 const canEditStage2 = hasStage2
47 const canAddStage2 = !hasStage2 && elapsed >= 1.5
48
49 // Stage 3 can be edited if it exists, or added after 4 hours
50 const canEditStage3 = hasStage3
51 const canAddStage3 = !hasStage3 && elapsed >= 4
52
53 return {
54 canEditStage1,
55 canEditStage2,
56 canEditStage3,
57 canAddStage2,
58 canAddStage3,
59 canEditText,
60 canChangeFragrance
61 }
62}
63
64/**
65 * Validates that a stage update is allowed based on timing and current state
66 */
67export function validateStageUpdate(
68 review: any,
69 stage: 'stage1' | 'stage2' | 'stage3'
70): { valid: boolean; error?: string } {
71 const permissions = validateEditPermissions(review)
72
73 if (permissions.error) {
74 return { valid: false, error: permissions.error }
75 }
76
77 if (stage === 'stage1') {
78 // Stage 1 can always be edited within 24 hours
79 if (!permissions.canEditStage1) {
80 return { valid: false, error: 'Stage 1 cannot be edited after 24 hours' }
81 }
82 }
83
84 if (stage === 'stage2') {
85 if (!permissions.canEditStage2 && !permissions.canAddStage2) {
86 const elapsed = calculateElapsedHours(review.createdAt)
87 if (elapsed < 1.5) {
88 const minsRemaining = Math.ceil((1.5 - elapsed) * 60)
89 return {
90 valid: false,
91 error: `Heart notes are available in ${minsRemaining} minutes`
92 }
93 }
94 return { valid: false, error: 'Stage 2 cannot be updated at this time' }
95 }
96 }
97
98 if (stage === 'stage3') {
99 if (!permissions.canEditStage3 && !permissions.canAddStage3) {
100 const elapsed = calculateElapsedHours(review.createdAt)
101 if (elapsed < 4) {
102 const minsRemaining = Math.ceil((4 - elapsed) * 60)
103 return {
104 valid: false,
105 error: `Final notes are available in ${minsRemaining} minutes`
106 }
107 }
108 const hasStage2 = !!(review.drydownRating && review.midProjection && review.sillage)
109 if (!hasStage2) {
110 return {
111 valid: false,
112 error: 'Stage 2 must be completed before adding Stage 3'
113 }
114 }
115 return { valid: false, error: 'Stage 3 cannot be updated at this time' }
116 }
117 }
118
119 return { valid: true }
120}
121
122/**
123 * Check if review's fragrance connection can be changed
124 * This is allowed at ANY time, even after 24 hours when other edits are locked
125 */
126export function canChangeFragrance(_review: any): boolean {
127 return true // Always allowed
128}