33const { faker } = require ( '@faker-js/faker' )
44const weighted = require ( 'weighted' )
55const generateId = require ( '../utils/id-generator' )
6+ const symptomTypesData = require ( '../../data/symptom-types.js' )
67
7- // Updated symptom types to match the form
8- const SYMPTOM_TYPES = {
9- 'Lump' : {
10- weight : 0.4 ,
8+ // Helper to convert lowercase to sentence case
9+ const toSentenceCase = ( str ) => str . charAt ( 0 ) . toUpperCase ( ) + str . slice ( 1 )
10+
11+ // Generator-specific configuration (weights, descriptions, etc.)
12+ // Keys match lowercase names from symptom-types.js
13+ const GENERATOR_CONFIG = {
14+ 'lump' : {
15+ weight : 0.25 ,
1116 requiresLocation : true ,
1217 descriptions : [
1318 "Hard lump that doesn't move" ,
@@ -17,8 +22,21 @@ const SYMPTOM_TYPES = {
1722 'Tender lump that varies with menstrual cycle'
1823 ]
1924 } ,
20- 'Swelling or shape change' : {
21- weight : 0.2 ,
25+ 'breast pain' : {
26+ weight : 0.35 , // Most common symptom
27+ requiresLocation : true ,
28+ descriptions : [
29+ 'Sharp pain in breast' ,
30+ 'Dull ache that comes and goes' ,
31+ 'Burning or stabbing sensation' ,
32+ 'Tenderness that varies with menstrual cycle' ,
33+ 'Constant throbbing pain' ,
34+ 'Pain when pressure applied' ,
35+ 'Shooting pain through breast'
36+ ]
37+ } ,
38+ 'swelling or shape change' : {
39+ weight : 0.15 ,
2240 requiresLocation : true ,
2341 descriptions : [
2442 'Change in size or shape of breast' ,
@@ -28,14 +46,15 @@ const SYMPTOM_TYPES = {
2846 'Visible dent or dimpling'
2947 ]
3048 } ,
31- 'Nipple change' : {
32- weight : 0.15 ,
49+ 'nipple change' : {
50+ weight : 0.1 ,
3351 requiresLocation : false , // Uses nippleChangeLocation instead
3452 nippleChangeTypes : [
3553 'bloody discharge' ,
3654 'other discharge' ,
37- 'inversion or shape change' ,
38- 'rash' ,
55+ 'inversion' ,
56+ 'rash or eczema' ,
57+ 'shape change' ,
3958 'colour change'
4059 ] ,
4160 nippleChangeDescriptions : {
@@ -46,10 +65,15 @@ const SYMPTOM_TYPES = {
4665 ]
4766 }
4867 } ,
49- 'Skin change' : {
50- weight : 0.15 ,
68+ 'skin change' : {
69+ weight : 0.13 ,
5170 requiresLocation : true ,
52- skinChangeTypes : [ 'dimples or indentation' , 'rash' , 'colour change' ] ,
71+ skinChangeTypes : [
72+ 'sores or cysts' ,
73+ 'dimples or indentation' ,
74+ 'rash' ,
75+ 'colour change'
76+ ] ,
5377 skinChangeDescriptions : {
5478 other : [
5579 'Orange peel texture' ,
@@ -58,30 +82,34 @@ const SYMPTOM_TYPES = {
5882 ]
5983 }
6084 } ,
61- 'Other ' : {
85+ 'other ' : {
6286 weight : 0.02 ,
6387 requiresLocation : true ,
6488 descriptions : [
6589 'Unusual sensation or tenderness' ,
6690 'Heaviness in breast' ,
6791 'Tingling sensation' ,
68- 'Unusual firmness' ,
69- 'Persistent pain'
92+ 'Unusual firmness'
7093 ]
7194 }
7295}
7396
74- // const DATE_RANGE_OPTIONS = [
75- // "Less than a week",
76- // "1 week to a month",
77- // "1 to 3 months",
78- // "3 months to a year",
79- // "1 to 3 years",
80- // "Over 3 years"
81- // ]
97+ // Build SYMPTOM_TYPES by merging data file with generator config
98+ // Use sentence case keys to match stored data format
99+ const SYMPTOM_TYPES = { }
100+ for ( const symptomType of symptomTypesData ) {
101+ const config = GENERATOR_CONFIG [ symptomType . name ]
102+ if ( config ) {
103+ const sentenceCaseName = toSentenceCase ( symptomType . name )
104+ SYMPTOM_TYPES [ sentenceCaseName ] = {
105+ ...config ,
106+ isSignificantByDefault : symptomType . isSignificantByDefault
107+ }
108+ }
109+ }
82110
83111const DATE_RANGE_OPTIONS = [
84- 'Less than 3 months' ,
112+ 'Less than 3 months' ,
85113 '3 months to a year' ,
86114 '1 to 3 years' ,
87115 'Over 3 years'
@@ -175,7 +203,7 @@ const generateSymptom = (options = {}) => {
175203
176204 // Generate dateType matching the form structure
177205 const dateTypeWeights = {
178- ...Object . fromEntries ( DATE_RANGE_OPTIONS . map ( ( range ) => [ range , 0.1 ] ) ) , // 60% total for ranges
206+ ...Object . fromEntries ( DATE_RANGE_OPTIONS . map ( ( range ) => [ range , 0.1 ] ) ) ,
179207 dateKnown : 0.3 ,
180208 notSure : 0.1
181209 }
@@ -190,6 +218,14 @@ const generateSymptom = (options = {}) => {
190218 dateAdded : new Date ( ) . toISOString ( )
191219 }
192220
221+ // Set significance based on type
222+ if ( typeData . isSignificantByDefault ) {
223+ symptom . isSignificant = true
224+ } else {
225+ // For non-significant-by-default types, randomly mark 10% as significant
226+ symptom . isSignificant = Math . random ( ) < 0.1
227+ }
228+
193229 // Add user who added the symptom
194230 if ( options . addedByUserId ) {
195231 symptom . addedByUserId = options . addedByUserId
@@ -213,7 +249,6 @@ const generateSymptom = (options = {}) => {
213249 // For range options, store the same value in approximateDuration
214250 symptom . approximateDuration = symptom . dateType
215251 }
216- // For range options and 'notSure', no additional date fields needed
217252
218253 // 30% chance the symptom has recently stopped
219254 symptom . hasStopped = Math . random ( ) < 0.3
@@ -227,10 +262,15 @@ const generateSymptom = (options = {}) => {
227262 symptom . isIntermittent = Math . random ( ) < 0.25
228263
229264 // Handle type-specific fields
230- if ( type === 'Other' ) {
231- symptom . otherLocationDescription = faker . helpers . arrayElement (
232- typeData . descriptions
233- )
265+ if ( type === 'Other' || type === 'Breast pain' ) {
266+ // Both Other and Breast pain use simple descriptions
267+ if ( type === 'Breast pain' ) {
268+ // Breast pain doesn't need otherDescription, but we can add to additionalInfo later
269+ } else {
270+ symptom . otherDescription = faker . helpers . arrayElement (
271+ typeData . descriptions
272+ )
273+ }
234274 } else if ( type === 'Nipple change' ) {
235275 const changeType = faker . helpers . arrayElement ( typeData . nippleChangeTypes )
236276 symptom . nippleChangeType = changeType
0 commit comments