eletrotupi / tcc/ frontend/app/entry/mood-components.tsx2454104ffdf8fa9a5a1ee482f58928417aa1fdc7
6.6 KB | 245 lines Raw
1
import React from 'react';
2
import {
3
  View,
4
  Text,
5
  ScrollView,
6
  Pressable,
7
  StyleSheet,
8
} from 'react-native';
9
import { router } from 'expo-router';
10
import { Ionicons } from '@expo/vector-icons';
11

12
import { ScaleSlider } from '@/components/ui/ScaleSlider';
13
import { Row, Grid } from '@/components/ui/LayoutHelpers';
14
import { Section, SectionHeader } from '@/components/ui/Sections';
15
import { Button } from '@/components/ui/Button';
16
import { Card } from '@/components/ui/Cards';
17
import { Theme } from '@/constants/theme';
18
import {
19
  MOOD_COMPONENTS,
20
  getMoodComponent,
21
  intensityLabel,
22
} from '@/constants/mood-components';
23

24
import {
25
  useMoodEntryStore,
26
} from '@/stores/moodEntry';
27

28
export default function MoodComponentsScreen() {
29
  const {
30
    selectedMood,
31
    components,
32
    addComponent,
33
    removeComponent,
34
    setComponentIntensity,
35
  } = useMoodEntryStore();
36

37
  const activeIds = components.map((c) => c.id);
38
  const available = MOOD_COMPONENTS.filter((d) => !activeIds.includes(d.id));
39

40
  const handleDone = () => {
41
    router.back();
42
  };
43

44
  return (
45
    <View style={styles.container}>
46

47
      {/* Header */}
48
      <View style={styles.header}>
49
        <Pressable onPress={() => router.back()} hitSlop={8}>
50
          <Ionicons name="close" size={24} color={Theme.colors.text} />
51
        </Pressable>
52
        <Text style={styles.headerTitle}>Editar Componentes</Text>
53
        <Pressable onPress={handleDone} hitSlop={8}>
54
          <Text style={styles.headerAction}>Pronto</Text>
55
        </Pressable>
56
      </View>
57

58
      <ScrollView
59
        contentContainerStyle={styles.content}
60
        showsVerticalScrollIndicator={false}
61
      >
62

63
        {/* Subtitle */}
64
        {selectedMood && (
65
          <View style={styles.subtitleBlock}>
66
            <Text style={styles.subtitleSmall}>Baseado no seu humor selecionado</Text>
67
            <Text style={styles.subtitleLarge}>{selectedMood.label}</Text>
68
          </View>
69
        )}
70

71
        {/* Active components */}
72
        {components.length > 0 && (
73
          <Section>
74
            <SectionHeader
75
              title="Intensidade dos Componentes"
76
              info={`Ativos: ${components.length}`} />
77

78
            {components.map((comp) => {
79
              const def = getMoodComponent(comp.id);
80
              if (!def) return null;
81

82
              return (
83
                <Card key={comp.id} style={styles.activeCard}>
84
                  {/* Card header */}
85
                  <Row style={styles.activeCardHeader}>
86
                    <View style={[styles.dot, { backgroundColor: def.color }]} />
87
                    <Text style={styles.activeCardLabel}>{def.label}</Text>
88
                    <Pressable
89
                      onPress={() => removeComponent(comp.id)}
90
                      hitSlop={8}
91
                    >
92
                      <Ionicons
93
                        name="remove-circle-outline"
94
                        size={22}
95
                        color="#F87171"
96
                      />
97
                    </Pressable>
98
                  </Row>
99

100
                  {/* Slider */}
101
                  <ScaleSlider
102
                    variant="compact"
103
                    label="Intensidade"
104
                    value={comp.intensity}
105
                    onValueChange={(v) => setComponentIntensity(comp.id, v)}
106
                    min={1}
107
                    max={3}
108
                    step={1}
109
                    minLabel="Suave"
110
                    maxLabel="Intensa"
111
                    style={styles.slider}
112
                  />
113
                </Card>
114
              );
115
            })}
116

117
          </Section>
118
        )}
119

120
        {/* Available to add */}
121
        {available.length > 0 && (
122
          <Section>
123
            <SectionHeader title="Adicionar outros" />
124
            <Grid gap={2}>
125
              {available.map((def) => (
126
                <Card key={def.id} style={styles.availableItem}>
127
                  <Pressable
128
                    onPress={() => addComponent(def.id)}
129
                    style={styles.availableItemInternalWrapper}
130
                  >
131
                    <Row gap={8} style={styles.availableInner}>
132
                      <View style={[styles.dot, { backgroundColor: def.color }]} />
133
                      <Text style={styles.availableLabel}>{def.label}</Text>
134
                    </Row>
135

136
                    <Ionicons
137
                      name="add-circle-outline"
138
                      size={20}
139
                      color={Theme.colors.light.smallAddButtonIcon}
140
                    />
141
                  </Pressable>
142
                </Card>
143
              ))}
144
            </Grid>
145
          </Section>
146
        )}
147
      </ScrollView>
148
    </View>
149
  );
150
}
151

152
const styles = StyleSheet.create({
153
  container: {
154
    flex: 1,
155
  },
156
  header: {
157
    flexDirection: 'row',
158
    justifyContent: 'space-between',
159
    alignItems: 'center',
160
    paddingHorizontal: Theme.spacing.containerPadding,
161
    paddingVertical: 16,
162
    borderBottomWidth: 1,
163
    borderBottomColor: Theme.colors.light.divider,
164
  },
165
  headerTitle: {
166
    fontSize: Theme.typography.bodyLg.fontSize,
167
    fontWeight: '700',
168
    color: Theme.colors.light.text,
169
  },
170
  headerAction: {
171
    fontSize: Theme.typography.bodyMd.fontSize,
172
    fontWeight: '600',
173
    color: Theme.colors.light.tint,
174
  },
175
  content: {
176
    padding: Theme.spacing.containerPadding,
177
    gap: Theme.spacing.sectionGap,
178
    paddingBottom: 120,
179
  },
180
  subtitleBlock: {
181
    alignItems: 'center',
182
    gap: 4,
183
  },
184
  subtitleSmall: {
185
    fontSize: Theme.typography.bodyMd.fontSize,
186
    color: Theme.colors.light.textSecondary,
187
  },
188
  subtitleLarge: {
189
    fontSize: 28,
190
    fontWeight: '700',
191
    color: Theme.colors.light.text,
192
  },
193
  section: {
194
    gap: Theme.spacing.cardGap,
195
  },
196
  sectionHeader: {
197
    justifyContent: 'space-between',
198
    alignItems: 'center',
199
  },
200
  activeCard: {
201
    padding: Theme.spacing.cardGap,
202
  },
203
  activeCardHeader: {
204
    alignItems: 'center',
205
    justifyContent: 'space-between',
206
    marginBottom: 16
207
  },
208
  activeCardLabel: {
209
    flex: 1,
210
    ... { ...Theme.typography.bodyLg, lineHeight: 24 },
211
    color: Theme.colors.light.text,
212
    marginLeft: 4,
213
  },
214
  dot: {
215
    width: 12,
216
    height: 12,
217
    borderRadius: 6,
218
    flexShrink: 0,
219
  },
220
  slider: {
221
    marginTop: 4,
222
  },
223
  availableItem: {
224
    flexDirection: 'row',
225
    justifyContent: 'space-between',
226
    alignItems: 'center',
227
    paddingHorizontal: 12,
228
    paddingVertical: 10,
229
  },
230
  availableItemInternalWrapper: {
231
    flexDirection: 'row',
232
    width: '100%',
233
    justifyContent: 'space-between',
234
    alignItems: 'center',
235
  },
236
  availableInner: {
237
    alignItems: 'center',
238
    flexShrink: 1,
239
  },
240
  availableLabel: {
241
    fontSize: Theme.typography.bodyMd.fontSize,
242
    fontWeight: '500',
243
    color: Theme.colors.light.text,
244
  }
245
});