298 lines
7.0 KiB
Vue
298 lines
7.0 KiB
Vue
<style>
|
|
.calendar {
|
|
width: 300px;
|
|
height: 400px;
|
|
display: inline-block;
|
|
}
|
|
.day {
|
|
width: 40px;
|
|
height: 40px;
|
|
border: 1px solid var(--border_color);
|
|
display: inline-block;
|
|
text-align: center;
|
|
font-size: 1.2em;
|
|
cursor: pointer;
|
|
}
|
|
.today {
|
|
font-weight: bold;
|
|
}
|
|
.day ~ .active {
|
|
|
|
background-color: var(--main-accent);
|
|
color: var(--body_bg_color);
|
|
}
|
|
.day ~ .has-data {
|
|
outline: #07f4f4;
|
|
outline-style: none;
|
|
outline-width: medium;
|
|
outline-style: none;
|
|
outline-offset: -4px;
|
|
outline-style: solid;
|
|
outline-width: 2px;
|
|
}
|
|
</style>
|
|
|
|
<template>
|
|
<div class="squire-box">
|
|
|
|
<h3>Cycle Tracking Beta
|
|
<span v-on:click="deleteData()">
|
|
<i class="clickable trash icon"></i>
|
|
</span>
|
|
</h3>
|
|
|
|
<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}`,
|
|
'has-data':cycleData[`${day}.${calendar.month}.${calendar.year}`],
|
|
}"
|
|
v-on:click="openDayData(`${day}.${calendar.month}.${calendar.year}`)">
|
|
{{ day }}
|
|
</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>
|
|
|
|
</div>
|
|
|
|
<div class="ui green save button" v-on:click="saveDayData">
|
|
Save
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { defineAsyncComponent } from 'vue'
|
|
|
|
import axios from 'axios'
|
|
|
|
export default {
|
|
name: 'CycleTracking',
|
|
components: {
|
|
'logo':defineAsyncComponent(() => import('@/components/LogoComponent.vue')),
|
|
},
|
|
data () {
|
|
return {
|
|
appWorkingDate: null,
|
|
fields:[],
|
|
defaultFields:[
|
|
{'type':'float','label':'Basil Temp', 'id':'BT'},
|
|
{'type':'range','label':'Cervical Mucus', 'id':'CM'},
|
|
{'type':'text','label':'Notes', 'id':'NO'},
|
|
],
|
|
cycleData: {},
|
|
dateCode: null,
|
|
openDay: [],
|
|
calendar: {
|
|
monthName: '',
|
|
month: '',
|
|
year: '',
|
|
days: [],
|
|
weekdays: ['S','M','T','W','T','F','S'],
|
|
today: 0,
|
|
},
|
|
}
|
|
},
|
|
beforeCreate() {
|
|
|
|
// Perform Login check
|
|
this.$root.loginGateway()
|
|
|
|
},
|
|
mounted(){
|
|
if(!this.$store.getters.getLoggedIn){
|
|
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)
|
|
]
|
|
|
|
this.dateCode = dateSetup.join('.')
|
|
|
|
this.setupCalendar(this.appWorkingDate)
|
|
|
|
this.fetchCycleData()
|
|
},
|
|
methods: {
|
|
saveField(fieldId, value){
|
|
this.openDay[fieldId] = value
|
|
},
|
|
openDayData(dateCode){
|
|
|
|
if(String(dateCode).split('.').length != 3){
|
|
console.log('Invalid Date Code')
|
|
return
|
|
}
|
|
|
|
this.dateCode = dateCode || this.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] || ''
|
|
})
|
|
|
|
this.openDay = currentDay
|
|
|
|
},
|
|
saveDayData(){
|
|
|
|
// remove empty keys
|
|
let cleanDayData = {}
|
|
Object.keys(this.openDay).forEach(key => {
|
|
if(this.openDay[key] != ''){
|
|
cleanDayData[key] = this.openDay[key]
|
|
}
|
|
})
|
|
|
|
this.cycleData[this.dateCode] = cleanDayData
|
|
|
|
// Update calendar
|
|
this.setupCalendar(this.appWorkingDate)
|
|
|
|
this.saveCycleData()
|
|
|
|
},
|
|
fetchCycleData(){
|
|
|
|
axios.post('/api/cycle-tracking/get')
|
|
.then(({ data }) => {
|
|
if(data.hasOwnProperty("text")){
|
|
|
|
let appData = null
|
|
try {
|
|
appData = JSON.parse(data.text)
|
|
} catch(e) {
|
|
console.log('Didnt parse json')
|
|
}
|
|
|
|
console.log(appData)
|
|
|
|
this.cycleData = appData?.cycleData || {}
|
|
this.fields = appData?.fields || []
|
|
|
|
this.$nextTick(() => {
|
|
this.setupFields()
|
|
this.openDayData(this.dateCode)
|
|
})
|
|
}
|
|
})
|
|
.catch(error => { this.$bus.$emit('notification', error) })
|
|
|
|
},
|
|
saveCycleData(){
|
|
|
|
const appData = JSON.stringify({
|
|
fields: this.fields,
|
|
cycleData: this.cycleData,
|
|
})
|
|
axios.post('/api/cycle-tracking/save', { cycleData:appData })
|
|
.then(response => {
|
|
{ this.$bus.$emit('notification', 'Data Saved') }
|
|
})
|
|
.catch(error => { this.$bus.$emit('notification', error) })
|
|
},
|
|
deleteData(){
|
|
axios.post('/api/cycle-tracking/save', { cycleData:'' })
|
|
.then(response => {
|
|
{ this.$bus.$emit('notification', 'Data Deleted') }
|
|
})
|
|
},
|
|
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.defaultFields[i])
|
|
}
|
|
}
|
|
},
|
|
setupCalendar(date){
|
|
// ------------
|
|
// setup calendar display
|
|
var y = date.getFullYear()
|
|
var m = date.getMonth()
|
|
|
|
var firstDay = new Date(y, m, 1);
|
|
var lastDay = new Date(y, m + 1, 0);
|
|
|
|
function getDaysInMonth(year, month) {
|
|
return new Date(year, month, 0).getDate();
|
|
}
|
|
|
|
const currentYear = date.getFullYear();
|
|
const currentMonth = date.getMonth() + 1;
|
|
this.calendar.monthName = date.toLocaleString("en-US", { month: "long" });
|
|
this.calendar.year = currentYear
|
|
const daysInCurrentMonth = getDaysInMonth(currentYear, currentMonth);
|
|
|
|
const monthStartDay = firstDay.getDay()
|
|
let days = Array(monthStartDay).fill("."); // Pad days to start on correct weekday
|
|
for (let i = 0; i < daysInCurrentMonth; i++) {
|
|
days.push(i+1)
|
|
}
|
|
this.calendar.days = days
|
|
|
|
// set today
|
|
this.calendar.today = date.getDate()
|
|
this.calendar.month = date.getMonth()+1
|
|
|
|
|
|
/*
|
|
October 2022
|
|
S M T W T F S
|
|
1 2 3 4 5 6
|
|
7 8 9
|
|
*/
|
|
|
|
// -------
|
|
}
|
|
}
|
|
}
|
|
</script> |