@@ -1,101 +1,423 @@
< style >
. calendar {
width : 300 px ;
height : 400 px ;
display : inline - block ;
. squire - box {
padding : 0 ! important ;
}
div . calendar {
width : calc ( 100 % - 20 px ) ;
min - height : 350 px ;
display : flex ;
margin : 5 px 10 px 15 px ;
flex - wrap : wrap ;
flex - direction : row ;
justify - content : flex - start ;
}
. day {
width: 40 px ;
height : 4 0px ;
/* width: calc(100% / 8);*/
flex : 0 0 calc ( 14.28 % - 2 px ) ;
height : 50 px ;
border : 1 px solid var ( -- border _color ) ;
display : inline - block ;
text - align : center ;
font - size : 1.2 em ;
cursor : pointer ;
/*overflow: hidden;*/
box - sizing : border - box ;
margin : 1 px ;
padding : 0 0 0 5 px ;
position : relative ;
}
. today {
font - weight : bold ;
}
. day ~ . active {
background - color : var ( -- main - accent ) ;
color : var ( -- body _bg _color ) ;
}
. day ~ . has - data {
outline : # 07 f4f4 ;
outline - style : none ;
outline - width : medium ;
outline - style : none ;
outline - offset : - 4 px ;
outline - style : solid ;
outline - width : 2 px ;
}
. today {
font - weight : bold ;
text - decoration : underline ;
}
. day ~ . active {
outline : # 07 f4f4 ;
outline - style : none ;
outline - width : medium ;
outline - style : none ;
outline - offset : - 1 px ;
outline - style : solid ;
outline - width : 3 px ;
}
. day ~ . has - data {
}
. day ~ . no - data {
background : # c7c7c787 ;
opacity : 0.6 ;
}
. day > . number {
position : absolute ;
top : 0 ;
right : 5 px ;
z - index : 10 ;
}
. day > . sex {
font - size : 0.7 em ;
border - radius : 5 px ;
background : rgba ( 249 , 0 , 0 , 0.15 ) ;
color : white ;
padding : 0 0 0 4 px ;
z - index : 10 ;
position : absolute ;
left : 0 ;
height : 26 px ;
}
. day > . period {
position : absolute ;
bottom : 1 px ;
left : 1 px ;
right : 1 px ;
height : 5 px ;
background : red ;
z - index : 10 ;
}
. day > . mucus {
position : absolute ;
bottom : 0 ;
left : 0 ;
right : 0 ;
min - height : 10 px ;
background : # abecff7d ;
z - index : 2 ;
}
. day > . notes {
}
. key - holder {
display : flex ;
width : 100 % ;
flex - wrap : wrap ;
flex - direction : row ;
justify - content : flex - start ;
}
. key - display {
/*width: calc(100% - 70px);*/
float : left ;
height : 50 px ;
box - sizing : border - box ;
padding : 10 px 0 0 10 px ;
/*flex-basis: 70%;*/
flex : 1 0 80 % ;
}
. option - buttons {
display : flex ;
width : 100 % ;
flex - wrap : wrap ;
flex - direction : column ;
}
. option - buttons > div . button {
flex : 1 ;
margin : 0 0 3 px 0 ;
text - align : left ;
}
< / style >
< template >
< div class = "squire-box" >
< h3 > Cycle Tracking Beta
< div class = "ui centered dividing header" >
< br >
Metric Tracking Beta
< span v -on :click = "deleteData()" >
< i class = "clickable trash icon" > < / i >
< / span >
< / h3 >
< i class = "clickable trash icon" > < / i >
< / span >
< / div >
<!-- data input -- >
< div class = "ui basic segment" >
< div class = "ui very compact grid" >
< div class = "ui twelve wide middle aligned column" >
< div class = "ui header" >
Entry for { { calendar . monthName } } , { { calendar . today } }
< / div >
< / div >
< div class = "ui four wide right aligned middle aligned column" >
< span v-if = "saving == 0" >
< i class = "heart icon" > < / i >
< / span >
< span v-if = "saving == 1" >
< i class = "asterisk icon" > < / i >
< / span >
< span v-if = "saving == 2" >
< i class = "sync loading icon" > < / i >
< / span >
< span v-if = "saving == 3" >
< i class = "green circle check icon" > < / i >
< / span >
< / div >
< / div >
< div class = "ui form" >
< div class = "ui compact grid" >
< div v-for = "field in fields" :class="defaultFields[field].width || 'eight wide column'" >
< ! - - field label display - - >
< div class = "ui very compact grid" >
< div class = "ui fourteen wide column" >
< i v-if = "defaultFields[field].icon" :class="`${defaultFields[field].icon} icon`" > < / i >
< b > { { defaultFields [ field ] . label } } < / b >
< / div >
< div class = "ui two wide right aligned column" >
< span v -on :click = "fieldRemove(field)" >
< i class = "grey clickable minus icon" > < / i >
< / span >
< / div >
< / div >
<!-- float -- >
< div v-if = "defaultFields[field].type == 'float'" class="ui fluid input" >
< input type = "text" :placeholder = "defaultFields[field].label" v -on : keyup = "e => saveField(field, e.target.value)" :value = "openDay[field]" >
< / div >
<!-- range -- >
< div v-if = "defaultFields[field].type == 'shortRange'" >
< div : class = "{green:(openDay[field] == 1)}" v -on : click = "saveField(field, 1)" class = "ui button" > 1 < / div >
< div : class = "{green:(openDay[field] == 2)}" v -on : click = "saveField(field, 2)" class = "ui button" > 2 < / div >
< div : class = "{green:(openDay[field] == 3)}" v -on : click = "saveField(field, 3)" class = "ui button" > 3 < / div >
< div : class = "{green:(openDay[field] == 4)}" v -on : click = "saveField(field, 4)" class = "ui button" > 4 < / div >
< div : class = "{green:(openDay[field] == 5)}" v -on : click = "saveField(field, 5)" class = "ui button" > 5 < / div >
< / div >
<!-- text area -- >
< div v-if = "defaultFields[field].type == 'text'" >
< textarea rows = "3" v -on : keyup = "e => saveField(field, e.target.value)" > { { openDay [ field ] } } < / textarea >
< / div >
<!-- boolean -- >
< div v-if = "defaultFields[field].type == 'boolean'" >
< div : class = "{green:(openDay[field] == 1)}" v -on : click = "saveField(field, 1)" class = "ui button" > Yes < / div >
< div : class = "{green:(openDay[field] == 2)}" v -on : click = "saveField(field, 2)" class = "ui button" > No < / div >
< / div >
< div v-if = "['sex','period','mucus','pms'].includes(defaultFields[field].type)" >
< div class = "option-buttons" >
< div : class = "{green:(openDay[field] == key)}" v -on : click = "saveField(field, key)" class = "ui compact button" v-for = "(item,key) in fieldTypes[defaultFields[field].type].split(',')" > {{ item }} < / div >
< / div >
< / div >
< / div >
< / div >
< / div >
< span class = "clickable" v -on :click = "toggleFolded('fieldOptions')" >
< i class = "tiny circular blue clickable plus icon" > < / i >
Add / Remove Fields
< / span >
< div class = "ui very compact grid" v-if = "folded.includes('fieldOptions')" >
< div class = "ui row" >
< div class = "eight wide column" >
< span >
< i class = "ui disabeld plus icon" > < / i >
< / span >
< b > Name < / b >
< / div >
< div class = "six wide column" >
< b > Type < / b >
< / div >
< / div >
< div class = "ui row" v-for = "(field,fieldId) in defaultFields" v-if="!fields.includes(fieldId)" >
< div class = "eight wide column" >
< span v -on :click = "fieldAdd(fieldId)" >
< i class = "ui clickable orange plus icon" > < / i >
< / span >
{ { field . label } }
< / div >
< div class = "six wide column" >
{ { fieldTypes [ field . type ] } }
< / div >
< div class = "two wide column" >
{ { openDay [ fieldId ] } }
< / div >
< / div >
< / div >
< / div >
<!-- day navigation -- >
< div class = "ui compact grid" >
< div class = "ui five wide right aligned column" >
< div class = "ui tiny basic compact button" v -on :click = "openDayData(getPreviousDay)" >
< i class = "caret left icon" > < / i >
Previous
< / div >
< / div >
< div class = "ui six wide center aligned column" >
< div class = "ui tiny basic compact button" v -on :click = "openDayData(getToday)" >
< i class = "caret down icon" > < / i >
Today
< / div >
< / div >
< div class = "ui five wide left aligned column" >
< div class = "ui tiny basic compact button" v -on :click = "openDayData(getNextDay)" >
Next
< i class = "caret right icon" > < / i >
< / div >
< / div >
< / div >
< div class = "ui very compact grid" >
< div class = "ui four wide column" >
< span v -on :click = "openDayData(getPreviousMonth)" >
< i class = "clickable caret square left outline icon" > < / i >
< / span >
< / div >
< div class = "ui eight wide center aligned column" >
< p > { { calendar . monthName } } , { { calendar . year } } < / p >
< / div >
< div class = "ui four wide right aligned column" >
< span v -on :click = "openDayData(getNextMonth)" >
< i class = "clickable caret square right outline icon" > < / i >
< / span >
< / div >
< / div >
< div class = "calendar" >
< p > { { calendar . monthName } } , { { calendar . year } } < / p >
< div v-for = "day in calendar.weekdays" class="day" >
{{ day }}
< / div >
< div v-for = "day in calendar.days" class="day"
: class = "{
'today':day == calendar.today,
'active':dateCode == `${day}.${calendar.month}.${calendar.year}`,
'active':calendar. dateCode == `${day}.${calendar.month}.${calendar.year}`,
'has-data':cycleData[`${day}.${calendar.month}.${calendar.year}`],
'no-data':showDayDataColor(day),
}"
v -on :click = "openDayData(`${day}.${calendar.month}.${calendar.year}`)" >
{ { day } }
< span class = "number" > {{ day } } < / span >
<!-- period display -- >
< span v-if = "isPeriod(day)" class="period" > < / span >
< ! - - sex display - - >
< span v-if = "isSex(day) > 0" class="sex" >
< span v-if = "isSex(day) == 1" >
< i class = "red heart icon" > < / i >
< / span >
< span v-if = "isSex(day) == 2" >
< i class = "red baby carriage icon" > < / i >
< / span >
< / span >
<!-- mucus display -- >
< span v-if = "isMucus(day)" class="mucus" :style="`top:${100-(isMucus(day)*22)}%`" >
< / span >
< / div >
< / div >
< div class = "ui form " >
< h3 > < input type = "text" v-model = "dateCode" v-on:keypress.enter="openDayData(dateCode)" > < / h3 >
< div class = "field" v-for = "field in fields" >
< label > { { field . label } } < / label >
< div v-for = "(value, key) in openDay ">
<! - - float - - >
< div v-if = "field.type == 'float' && field.id == key" class="ui left icon input" >
< input type = "text" :placeholder = "field.label" v -on : keyup = "e => saveField(field.id, e.target.value)" :value = "value" >
< i class = "thermometer half icon" > < / i >
< / div >
<!-- range -- >
< div v-if = "field.type == 'range' && field.id == key" >
< div : class = "{green:(value == 1)}" v -on : click = "saveField(field.id, 1)" class = "ui button" > 1 < / div >
< div : class = "{green:(value == 2)}" v -on : click = "saveField(field.id, 2)" class = "ui button" > 2 < / div >
< div : class = "{green:(value == 3)}" v -on : click = "saveField(field.id, 3)" class = "ui button" > 3 < / div >
< div : class = "{green:(value == 4)}" v -on : click = "saveField(field.id, 4)" class = "ui button" > 4 < / div >
< div : class = "{green:(value == 5)}" v -on : click = "saveField(field.id, 5)" class = "ui button" > 5 < / div >
< / div >
<!-- text area -- >
< div v-if = "field.type == 'text' && field.id == key" >
< textarea rows = "3" v -on : keyup = "e => saveField(field.id, e.target.value)" >
{ { value } }
< / textarea >
< / div >
< div class = "ui basic segment " >
< div class = "ui clickable" v -on :click = "toggleFolded('key')" >
< i class = "tiny circular blue clickable plus icon" > < / i >
Calendar Explanation
< / div >
< div class = "ui segment key-holder" v-if = "folded.includes('key') ">
< div class = "day" >
<span class = "number" > 1 < / span >
< span class = "period" > < / span >
< / div >
< span class = "key-display" >
Period in Progress
< / span >
< / div >
< div class = "day" >
< span class = "number" > 1 < / span >
< span class = "mucus" :style = "`top:50%`" >
< / span >
< / div >
< span class = "key-display" >
Amount of cervical mucus
< / span >
< div class = "ui green save button" v -on :click = "saveDayData " >
Save
< div class = "day " >
< span class = "number" > 1 < / span >
< span class = "sex" >
< span >
< i class = "red heart icon" > < / i >
< / span >
< / span >
< / div >
< span class = "key-display" >
Had sex with contraception
< / span >
< div class = "day" >
< span class = "number" > 1 < / span >
< span class = "sex" >
< span >
< i class = "red baby carriage icon" > < / i >
< / span >
< / span >
< / div >
< span class = "key-display" >
Had sex without contraception
< / span >
< div class = "day no-data" >
< span class = "number" > 1 < / span >
< / div >
< span class = "key-display" >
No Data entered
< / span >
< / div >
< / div >
<!-- Temp graph -- >
< div class = "ui basic segment" >
< div class = "ui dividing header" >
Basil temp last { { tempChartDays } } days
< / div >
< div class = "ui tiny compact basic fluid buttons" >
< div : class = "{'green':(tempChartDays == 1000000)}" v -on : click = "tempChartDays = 1000000; graphCurrentData()" class = "ui button" > ALL < / div >
< div : class = "{'green':(tempChartDays == 360)}" v -on : click = "tempChartDays = 360; graphCurrentData()" class = "ui button" > 360 < / div >
< div : class = "{'green':(tempChartDays == 180)}" v -on : click = "tempChartDays = 180; graphCurrentData()" class = "ui button" > 180 < / div >
< div : class = "{'green':(tempChartDays == 90)}" v -on : click = "tempChartDays = 90; graphCurrentData()" class = "ui button" > 90 < / div >
< div : class = "{'green':(tempChartDays == 60)}" v -on : click = "tempChartDays = 60; graphCurrentData()" class = "ui button" > 60 < / div >
< div : class = "{'green':(tempChartDays == 30)}" v -on : click = "tempChartDays = 30; graphCurrentData()" class = "ui button" > 30 < / div >
< div : class = "{'green':(tempChartDays == 7)}" v -on : click = "tempChartDays = 7; graphCurrentData()" class = "ui button" > 7 < / div >
< / div >
< div id = "graphdiv" style = "width: 100%; min-height: 320px;" > < / div >
< / div >
<!-- notes -- >
< div class = "ui basic segment" >
< div class = "ui clickable" v -on :click = "toggleFolded('notes')" >
< i class = "tiny circular blue clickable plus icon" > < / i >
Additional Notes
< / div >
< div class = "ui fitted segments" v-if = "folded.includes('notes')" >
< div class = "ui segment" >
< a href = "https://www.plannedparenthood.org/learn/birth-control/fertility-awareness" > Further Reading on planned parenthood . < / a >
< / div >
< div class = "ui segment" >
Follicular phase
Luteal phase
< / div >
< div class = "ui segment" >
Ovulation is detected by sustained temperate elevation . < br >
Ovulation can only be determined in hindsight , as progesterone is what makes the temperatures rise , and progesterone is only produced in abundance post - ovulation .
< / div >
< div class = "ui segment" >
Some people may find that their temperature drops the day before or the day their period arrives . This is a very helpful sign in knowing that your period is on it ’ s way !
< / div >
< div class = "ui segment" >
About halfway through your menstrual cycle , your hormones tell one of your ovaries to release a mature egg — this is called ovulation . Most people don ’ t feel it when they ovulate , but some ovulation symptoms are bloating , spotting , or a little pain in your lower belly that you may only feel on one side .
< / div >
< div class = "ui segment" >
If you do get pregnant , your body needs the lining — that ’ s why your period stops during pregnancy . Your period comes back when you ’ re not pregnant anymore .
< / div >
< / div >
< / div >
<!-- spacer at the bottom for mobile menu -- >
< div class = "ui basic segment" > < / div >
<!-- may or may not need digraph CSS , maybe disect -- >
<!-- < link rel = "stylesheet" href = "//cdnjs.cloudflare.com/ajax/libs/dygraph/2.1.0/dygraph.min.css" / > -- >
< / div >
< / template >
@@ -103,24 +425,50 @@
import axios from 'axios'
var BASAL _TEMP = 'BT'
export default {
name : 'Cycle Tracking' ,
name : 'Metric Tracking' ,
components : {
'logo' : require ( '@/components/LogoComponent.vue' ) . default ,
} ,
data ( ) {
return {
appWorkingDate : null ,
folded : [ ] ,
working : true ,
showNotes : false ,
fields : [ ] ,
defaultField s: [
{ 'type' : 'float' , 'label' : 'Basil Temp' , 'id' : 'BT' } ,
{ 'type' : 'range' , 'label' : 'Cervical Mucus' , 'id' : 'CM' } ,
{ 'type' : 'text' , 'label' : 'Notes' , 'id' : 'NO' } ,
] ,
fieldType s: {
'float' : 'Precise Number' ,
'shortRange' : 'Options 1-5' ,
'longRange' : 'Options 1-10' ,
'text' : 'Text Input' ,
'boolean' : 'Yes, No' ,
'period' : 'No, 1. Light, 2. Normal, 3. Heavy, 4. Irregular, 5. Painful' ,
'mucus' : 'None, 1. Watery, 2. Eggwhite, 3. Creamy, 4. Sticky' ,
'sex' : 'None, With contraception, Without contraception' ,
'pms' : 'No, 1. Maybe, 2. A little, 3. Real Cranky' ,
} ,
defaultFields : {
'BT' : { 'type' : 'float' , 'label' : 'Basal Temp' , 'icon' : 'thermometer half' , 'width' : 'sixteen wide column' } ,
'CM' : { 'type' : 'mucus' , 'label' : 'Cervical Mucus' , 'icon' : '' , 'width' : 'eight wide column' } ,
'PE' : { 'type' : 'period' , 'label' : 'Having Period' , 'icon' : '' , 'width' : 'eight wide column' } ,
'SE' : { 'type' : 'sex' , 'label' : 'Sex' , 'icon' : '' , 'width' : 'eight wide column' } ,
'NO' : { 'type' : 'text' , 'label' : 'Notes' , 'icon' : '' , 'width' : 'sixteen wide column' } ,
'OV' : { 'type' : 'boolean' , 'label' : 'Suspect Ovulation' , 'icon' : '' , 'width' : '' } ,
'PM' : { 'type' : 'pms' , 'label' : 'PMS' , 'icon' : '' , 'width' : '' } ,
'HO' : { 'type' : 'boolean' , 'label' : 'Horny' , 'icon' : '' , 'width' : '' } ,
'DI' : { 'type' : 'text' , 'label' : 'Diet' , 'icon' : '' , 'width' : '' } ,
'EX' : { 'type' : 'text' , 'label' : 'Exercise' , 'icon' : '' , 'width' : '' } ,
} ,
cycleData : { } ,
dateCode : null ,
openDay : [ ] ,
totalEntries : 0 ,
openDay : { } ,
saveDataDebounce : null ,
saving : 0 , // 0 blank, 1 modified, 2 saving, 3 saved
calendar : {
dateObject : null ,
dateCode : null ,
monthName : '' ,
month : '' ,
year : '' ,
@@ -128,6 +476,7 @@
weekdays : [ 'S' , 'M' , 'T' , 'W' , 'T' , 'F' , 'S' ] ,
today : 0 ,
} ,
tempChartDays : 60 ,
}
} ,
beforeCreate ( ) {
@@ -141,25 +490,178 @@
return
}
// setup date code
// day - month - year
const now = new Date ( )
this . appWorkingDate = now
const dateSetup = [
now . getDate ( ) , // 1-31 (Day)
now . getMonth ( ) + 1 , // 0-11 (Month)
now . getFullYear ( ) , // 1888-2022 (Year)
]
// set up reactive open day object
Object . keys ( this . defaultFields ) . forEach ( fieldId => {
this . $set ( this . openDay , fieldId , '' )
} )
this . dateCode = dateSetup . join ( '.' )
// Include JS libraries
let graphs = document . createElement ( 'script' )
graphs . setAttribute ( 'src' , '//cdnjs.cloudflare.com/ajax/libs/dygraph/2.1.0/dygraph.min.js' )
document . head . appendChild ( graphs )
this . setupCalendar ( this . appWorkingDate )
// setup date to today
this . setupCalendar ( )
this . fetchCycleData ( )
} ,
computed : {
getToday ( ) {
return this . generateDateCode ( new Date ( ) )
} ,
getPreviousDay ( ) {
const workingDate = this . calendar . dateObject || new Date ( )
workingDate . setDate ( workingDate . getDate ( ) - 1 )
return this . generateDateCode ( workingDate )
} ,
getNextDay ( ) {
const workingDate = this . calendar . dateObject || new Date ( )
workingDate . setDate ( workingDate . getDate ( ) + 1 )
return this . generateDateCode ( workingDate )
} ,
getNextMonth ( ) {
const workingDate = this . calendar . dateObject || new Date ( )
workingDate . setMonth ( workingDate . getMonth ( ) + 1 )
return this . generateDateCode ( workingDate )
} ,
getPreviousMonth ( ) {
const workingDate = this . calendar . dateObject || new Date ( )
workingDate . setMonth ( workingDate . getMonth ( ) - 1 )
return this . generateDateCode ( workingDate )
} ,
} ,
methods : {
toggleFolded ( key ) {
const index = this . folded . indexOf ( key )
if ( index == - 1 ) {
this . folded . push ( key )
return
}
this . folded . splice ( index , 1 )
} ,
showDayDataColor ( day ) {
// Determine if day has any data set
if ( day == '' ) {
return false
}
return ! ( this . cycleData [ ` ${ day } . ${ this . calendar . month } . ${ this . calendar . year } ` ] )
} ,
isPeriod ( day ) {
const data = this . cycleData [ ` ${ day } . ${ this . calendar . month } . ${ this . calendar . year } ` ]
if ( data ? . PE > 0 ) {
return true
}
} ,
isSex ( day ) {
const data = this . cycleData [ ` ${ day } . ${ this . calendar . month } . ${ this . calendar . year } ` ]
return data ? . SE
} ,
isMucus ( day ) {
const data = this . cycleData [ ` ${ day } . ${ this . calendar . month } . ${ this . calendar . year } ` ]
return data ? . CM
} ,
isNotes ( day ) {
const data = this . cycleData [ ` ${ day } . ${ this . calendar . month } . ${ this . calendar . year } ` ]
return data ? . NO
} ,
isTemp ( day ) {
const data = this . cycleData [ ` ${ day } . ${ this . calendar . month } . ${ this . calendar . year } ` ]
return data ? . BT
} ,
fieldRemove ( field ) {
for ( let i = this . fields . length - 1 ; i >= 0 ; i -- ) {
if ( field == this . fields [ i ] ) {
this . fields . splice ( i , 1 )
break
}
}
this . saveCycleData ( )
} ,
fieldAdd ( fieldId ) {
this . fields . push ( fieldId )
this . saveCycleData ( )
} ,
graphCurrentData ( ) {
// CSV or path to a CSV file.
let dataString = "Date,Temperature,Average\n"
// Excel date format YYYYMMDD
const convertToExcelDate = ( dateCode ) => {
return dateCode
. split ( '.' )
. reverse ( )
. map ( item => String ( item ) . padStart ( 2 , 0 ) )
. join ( '' )
}
const dataKeys = Object . keys ( this . cycleData )
// calculate average
let average = 0.0
let totalTemps = 0
for ( var i = 0 ; i < dataKeys . length ; i ++ ) {
const current = this . cycleData [ dataKeys [ i ] ]
if ( current . BT ) {
average += parseFloat ( current . BT )
totalTemps ++
}
}
average = ( average / totalTemps )
// build CSV data
for ( var i = 0 ; i < dataKeys . length ; i ++ ) {
const current = this . cycleData [ dataKeys [ i ] ]
let nextFragment = [ ]
// push date code
nextFragment . push ( convertToExcelDate ( dataKeys [ i ] ) )
if ( current . BT ) {
// parse temp to fixed length float 00.00
nextFragment . push ( parseFloat ( current . BT ) . toFixed ( 2 ) )
} else {
continue
}
nextFragment . push ( average )
dataString += nextFragment . join ( ',' ) + "\n"
if ( i >= this . tempChartDays ) {
break
}
}
let graphDiv = document . getElementById ( "graphdiv" )
const graphOptions = {
animatedZoom : true ,
}
const g = new Dygraph ( graphDiv , dataString , graphOptions )
} ,
saveField ( fieldId , value ) {
this . openDay [ fieldId ] = value
// Dont save value if it hasn't changed
if ( this . openDay [ fieldId ] == value ) { return }
// update field to be reactive
this . $set ( this . openDay , fieldId , value )
// remove debounce and set to modified
this . $nextTick ( ( ) => {
//0 blank, 1 modified, 2 saving, 3 saved
this . saving = 1
clearTimeout ( this . saveDataDebounce )
this . saveDataDebounce = setTimeout ( ( ) => {
this . saveDayData ( )
} , 500 )
} )
} ,
openDayData ( dateCode ) {
@@ -168,16 +670,14 @@
return
}
this . dateCode = dateCode || this . dateCode
this . setupCalendar ( this . dateCodeToDate ( dateCode ) )
let currentDay = this . cycleData [ this . dateCode ] || { }
//Set up each entry empty or with current value
this . fields . forEach ( field => {
currentDay [ field . id ] = currentDay [ field . id ] || ''
// open day has all fields defined, just set values
let currentDay = this . cycleData [ dateCode ] || { }
Object . keys ( this . openDay ) . forEach ( fieldId => {
this . openDay [ fieldId ] = currentDay [ fieldId ] || ''
} )
this . openDay = currentDay
} ,
saveDayData ( ) {
@@ -185,15 +685,18 @@
// remove empty keys
let cleanDayData = { }
Object . keys ( this . openDay ) . forEach ( key => {
if ( this . openDay [ key ] != '' ) {
if ( this . openDay [ key ] != '' && this . openDay [ key ] != 0 ) {
cleanDayData [ key ] = this . openDay [ key ]
}
} )
this . cycleData [ this . dateCode ] = cleanDayD ata
// Only save entry if there is d ata
delete this . cycleData [ this . calendar . dateCode ]
if ( Object . keys ( cleanDayData ) . length > 0 ) {
this . cycleData [ this . calendar . dateCode ] = cleanDayData
}
// Update calendar
this . setupCalendar ( this . appWorkingDate )
this . graphCurrentData ( )
this . saveCycleData ( )
@@ -211,14 +714,20 @@
console . log ( 'Didnt parse json' )
}
console. log ( appData )
// console.clear()
// console.log(appData)
this . cycleData = appData ? . cycleData || { }
this . fields = appData ? . fields || [ ]
this . $nextTick ( ( ) => {
this . totalEntries = Object . keys ( this . cycleData ) . length
this . setupFields ( )
this . openDayData ( this . dateCode )
this . openDayData ( this . calendar . dateCode)
this . graphCurrentData ( )
this . generateTonsOfRandomData ( )
} )
}
} )
@@ -231,9 +740,17 @@
fields : this . fields ,
cycleData : this . cycleData ,
} )
// 0 blank, 1 modified, 2 saving, 3 saved
this . saving = 2 // Working
this . totalEntries = Object . keys ( this . cycleData ) . length
axios . post ( '/api/cycle-tracking/save' , { cycleData : appData } )
. then ( response => {
{ this . $bus . $emit ( 'notification', 'Data Saved') }
// { this.$bus.$emit( 'notification', 'Data Saved') }
this . saving = 3 //Saved
setTimeout ( ( ) => {
this . saving = 0 //Reset
} , 2000 )
} )
. catch ( error => { this . $bus . $emit ( 'notification' , error ) } )
} ,
@@ -241,18 +758,54 @@
axios . post ( '/api/cycle-tracking/save' , { cycleData : '' } )
. then ( response => {
{ this . $bus . $emit ( 'notification' , 'Data Deleted' ) }
this . fetchCycleData ( )
} )
} ,
setupFields ( ) {
// push the first 3 default fields to users set
if ( this . fields . length == 0 ) {
for ( let i = 0 ; i < 3 ; i ++ ) {
this . fields . push ( this . defaultF iel ds[ i ] )
const fieldKeys = Object . keys ( this . defaultFields )
console . log ( 'Setup default f ier ds' )
for ( let i = 0 ; i < 5 ; i ++ ) {
this . fields . push ( fieldKeys [ i ] )
}
}
} ,
generateDateCode ( date ) {
const dateSetup = [
date . getDate ( ) , // 1-31 (Day)
date . getMonth ( ) + 1 , // 0-11 (Month)
date . getFullYear ( ) , // 1888-2022 (Year)
]
return dateSetup . join ( '.' )
} ,
dateCodeToDate ( dateCode ) {
const dateChunk = dateCode . split ( '.' )
return new Date ( dateChunk [ 2 ] , dateChunk [ 1 ] - 1 , dateChunk [ 0 ] )
} ,
setupCalendar ( date ) {
this . working = true
setTimeout ( ( ) => {
this . working = false
} , 500 )
if ( ! date && this . dateObject ) {
date = this . dateObject
}
if ( ! date ) {
date = new Date ( )
}
this . calendar . dateObject = date
this . calendar . dateCode = this . generateDateCode ( date )
// ------------
// setup calendar display
var y = date . getFullYear ( )
@@ -272,7 +825,7 @@
const daysInCurrentMonth = getDaysInMonth ( currentYear , currentMonth ) ;
const monthStartDay = firstDay . getDay ( )
let days = Array ( monthStartDay ) . fill ( ". " ) ; // Pad days to start on correct weekday
let days = Array ( monthStartDay ) . fill ( "" ) ; // Pad days to start on correct weekday
for ( let i = 0 ; i < daysInCurrentMonth ; i ++ ) {
days . push ( i + 1 )
}
@@ -291,7 +844,33 @@
*/
// -------
}
} ,
generateTonsOfRandomData ( ) {
return
let workingDate = new Date ( )
for ( var i = 0 ; i < 365 * 2 ; i ++ ) {
const cycleTime = ( i % 30 ) + 1
const randomInt = Math . floor ( Math . random ( ) * cycleTime + 20 ) + ( cycleTime ) ;
let randomTemp = parseFloat ( ` 97. ${ randomInt } ` )
const randomFive = Math . floor ( Math . random ( ) * 4 ) + 0 ;
const randomHundo = Math . floor ( Math . random ( ) * 100 ) + 1 ;
const randUnoOrDuo = Math . floor ( Math . random ( ) * 2 ) + 1 ;
this . cycleData [ this . generateDateCode ( workingDate ) ] = {
'BT' : randomTemp ,
'CM' : randomFive ,
'SE' : randomHundo > 90 ? randUnoOrDuo : 0 ,
}
workingDate . setDate ( workingDate . getDate ( ) - 1 )
}
this . graphCurrentData ( 5000 )
} ,
}
}
< / script >