From 1b7b33d43fe155e291f6cdf929d925b9c1b450ce Mon Sep 17 00:00:00 2001
From: Rifa Achrinza <25147899+achrinza@users.noreply.github.com>
Date: Tue, 8 Oct 2024 16:53:04 +0800
Subject: [PATCH] feat: initial diary and graph components
Signed-off-by: Rifa Achrinza <25147899+achrinza@users.noreply.github.com>
---
app/calendar/index.tsx | 51 +++++++++
app/diary/index.tsx | 254 +++++++++++++++++++++++++++++++++++++++++
components/Graph.tsx | 124 ++++++++++++++++++++
3 files changed, 429 insertions(+)
create mode 100644 app/calendar/index.tsx
create mode 100644 app/diary/index.tsx
create mode 100644 components/Graph.tsx
diff --git a/app/calendar/index.tsx b/app/calendar/index.tsx
new file mode 100644
index 0000000..da1b000
--- /dev/null
+++ b/app/calendar/index.tsx
@@ -0,0 +1,51 @@
+import moment from 'moment';
+import {Text, View} from 'react-native';
+
+export type CalendarProps = {
+ view: 'week' | 'month';
+ activeWeekOrMonth?: number;
+ activeYear?: number;
+ selectedDate: Date;
+};
+
+export function Calendar({
+ view,
+ activeWeekOrMonth,
+ activeYear,
+ selectedDate,
+}: CalendarProps) {
+ function isLeapYear(year: number) {
+ if (year % 4 !== 0) return false;
+ if (year % 100 === 0 && year % 400 !== 0) return false;
+ return true;
+ }
+
+ const activeMonth = selectedDate.getUTCMonth();
+ activeYear = selectedDate.getUTCFullYear();
+ const activeMonthStartDay = selectedDate.getDay();
+
+ const monthDayCount = [
+ 31,
+ (() => (isLeapYear(activeYear) ? 29 : 28))(),
+ 31,
+ 30,
+ 31,
+ 30,
+ 31,
+ 31,
+ 30,
+ 31,
+ 30,
+ 31,
+ ];
+
+ const monthStartDay = activeMonth;
+
+ return (
+
+ {moment('MMMM')}
+
+ );
+}
+
+export default function CalendarWrapper() {}
diff --git a/app/diary/index.tsx b/app/diary/index.tsx
new file mode 100644
index 0000000..2b89da3
--- /dev/null
+++ b/app/diary/index.tsx
@@ -0,0 +1,254 @@
+import {ScrollView, StyleSheet, Text, View} from 'react-native';
+import {Graph} from '@/components/Graph';
+
+function GraphSection({title, subtitle, children}) {
+ const styles = StyleSheet.create({
+ root: {
+ alignItems: 'center',
+ maxWidth: 400,
+ marginVertical: 30,
+ },
+ title: {
+ color: '#765000',
+ fontWeight: 'bold',
+ fontSize: 24,
+ alignSelf: 'stretch',
+ },
+ subtitle: {
+ color: '#765000',
+ fontSize: 16,
+ alignSelf: 'stretch',
+ },
+ chartContainer: {
+ marginTop: 30,
+ height: 200,
+ width: 300,
+ alignItems: 'center',
+ },
+ });
+
+ return (
+
+ {title}
+ {subtitle}
+ {children}
+
+ );
+}
+
+type InsightsProps = {
+ insights: {
+ trend: 'up' | 'down';
+ text: string;
+ }[];
+};
+
+export function Insights({insights}: InsightsProps) {
+ const styles = StyleSheet.create({
+ root: {
+ borderRadius: 12,
+ paddingVertical: 12,
+ paddingHorizontal: 12,
+ backgroundColor: '#765000',
+ },
+ title: {
+ color: '#FFF',
+ fontWeight: 'bold',
+ fontSize: 20,
+ },
+ text: {
+ color: '#FFF',
+ fontSize: 16,
+ },
+ insight: {
+ flexDirection: 'row',
+ },
+ });
+
+ return (
+
+ Insights
+ {insights.map(({trend, text}, index) => (
+
+ {trend}
+ {text}
+
+ ))}
+
+ );
+}
+
+type Recommendation = {
+ title: string;
+ backgroundColor: string;
+ image: object;
+ onPress?: object;
+};
+
+type RecommendationsProps = {
+ recommendations: Recommendation[];
+};
+
+function Recommendations({recommendations}: RecommendationsProps) {
+ const styles = StyleSheet.create({
+ root: {
+ marginVertical: 30,
+ },
+ title: {
+ color: '#765000',
+ fontWeight: 'bold',
+ fontSize: 24,
+ alignSelf: 'stretch',
+ },
+ recommendationContainer: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ recommendation: {
+ borderRadius: 30,
+ padding: 20,
+ width: '30%',
+ maxWidth: 200,
+ },
+ recommendationText: {
+ fontWeight: 'bold',
+ fontSize: 14,
+ },
+ });
+
+ return (
+
+ Recommended
+
+ {recommendations.map(({title, image, backgroundColor}, i) => (
+
+ {title}
+
+ ))}
+
+
+ );
+}
+
+export default function Demo() {
+ const styles = StyleSheet.create({
+ root: {
+ backgroundColor: '#FFF',
+ margin: 20,
+ },
+ title: {
+ fontSize: 30,
+ textAlign: 'center',
+ color: '#756000',
+ fontWeight: 'bold',
+ },
+ });
+
+ const recommendations: Recommendation[] = [
+ {
+ title: 'How to feel better article',
+ backgroundColor: '#A1AEFF',
+ image: {},
+ },
+ {
+ title: 'Try Deep Breathing',
+ backgroundColor: '#AEFFA1',
+ image: {},
+ },
+ {
+ title: 'Anxiety and Panic Attack',
+ backgroundColor: '#FFE7E7',
+ image: {},
+ },
+ ];
+
+ return (
+
+ My Diary
+
+
+
+
+
+
+
+
+
+ );
+}
+
+const pointColors = [
+ '#8DFAB7',
+ '#FADC8D',
+ '#8DD0FA',
+ '#FA9C93',
+ '#FADC8D',
+ '#FADC8D',
+ '#FADC8D',
+];
+
+const scalesData = [
+ {
+ point: 50,
+ label: 'M',
+ label2: '18',
+ },
+ {
+ point: 20,
+ label: 'T',
+ label2: '19',
+ },
+ {
+ point: 30,
+ label: 'W',
+ label2: '20',
+ },
+ {
+ point: 60,
+ label: 'T',
+ label2: '21',
+ highlight: true,
+ },
+ {
+ point: 20,
+ label: 'F',
+ label2: '22',
+ },
+ {
+ point: 30,
+ label: 'S',
+ label2: '23',
+ },
+ {
+ point: 90,
+ label: 'S',
+ label2: '24',
+ },
+];
diff --git a/components/Graph.tsx b/components/Graph.tsx
new file mode 100644
index 0000000..1795dca
--- /dev/null
+++ b/components/Graph.tsx
@@ -0,0 +1,124 @@
+import {StyleSheet, Text, View} from 'react-native';
+
+export type GraphProps = {
+ style?: CommonStyleProps;
+ min?: number;
+ max?: number;
+ scales: ScaleProps[];
+};
+
+type CommonStyleProps = {
+ pointColors?: string[];
+ pointHeight?: number;
+ pointColor?: string;
+ slideWidth?: number;
+ slideGap?: number;
+ slideColor?: string;
+};
+
+type ScaleProps = {
+ style?: CommonStyleProps;
+ point: number;
+ label?: string;
+ label2?: string;
+ color?: string;
+ min?: number;
+ max?: number;
+ highlight?: boolean;
+};
+
+function Scale({
+ style,
+ label,
+ label2,
+ point,
+ color,
+ min,
+ max,
+ highlight,
+}: ScaleProps) {
+ const slideColor = style?.slideColor || '#F7F7F7';
+ const slideWidth = style?.slideWidth || 25;
+ const pointHeight = style?.pointHeight || 25;
+ const pointColor = color || 'red';
+ min = min || 0;
+ max = max || 100;
+ const pointPosition = `${((point - min) / max) * 100}%`;
+
+ const styles = StyleSheet.create({
+ slideOuter: {
+ height: '100%',
+ alignItems: 'center',
+ },
+ slideInner: {
+ backgroundColor: slideColor,
+ borderRadius: 6,
+ width: slideWidth,
+ flexGrow: 1,
+ },
+ point: {
+ position: 'absolute',
+ // @ts-ignore
+ bottom: pointPosition,
+ backgroundColor: pointColor,
+ borderRadius: 6,
+ height: pointHeight,
+ width: '100%',
+ },
+ label: {
+ fontSize: 20,
+ },
+ label2: {
+ fontSize: 20,
+ fontWeight: 900,
+ },
+ labelHighlight: {
+ borderWidth: 3,
+ borderColor: '#DDD',
+ borderRadius: 5000,
+ },
+ });
+
+ return (
+
+
+
+
+ {label ? label : ' '}
+
+ {label2 ? label2 : ' '}
+
+
+ );
+}
+
+export function Graph({style, scales, min, max}: GraphProps) {
+ const styles = StyleSheet.create({
+ root: {
+ height: '100%',
+ width: '100%',
+ gap: 25,
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ });
+
+ return (
+
+ {scales.map(({point, color, label, label2}, index) => (
+
+ ))}
+
+ );
+}