eletrotupi / tcc/ frontend/app/entry/post-mood-links.tsxb77de0cf2fd487c62b9c698932d65906b0ef9398
6.5 KB | 199 lines Raw
1
import { View, TouchableOpacity, ScrollView, StyleSheet, ActivityIndicator } from 'react-native';
2
import { Text } from '@/components/ui/Text';
3
import { useState } from 'react';
4
import { router, useLocalSearchParams } from 'expo-router';
5
import { Ionicons, MaterialIcons } from '@expo/vector-icons';
6
import { Button } from '@/components/ui/Button';
7
import { Section, SectionHeader } from '@/components/ui/Sections';
8
import { Spacing, Typography, Colors, BorderRadius } from '@/constants/theme';
9
import { useTriggers, useLinkMoodToTrigger } from '@/hooks';
10
import { getTriggerCategory } from '@/constants/trigger-categories';
11
import { Trigger } from '@/lib/api';
12

13
type FlowState = 'PICK_TRIGGER' | 'PICK_IMPACT';
14

15
export default function PostMoodLinks() {
16
  const { moodId } = useLocalSearchParams<{ moodId: string }>();
17
  const [flowState, setFlowState] = useState<FlowState>('PICK_TRIGGER');
18
  const [selectedTrigger, setSelectedTrigger] = useState<Trigger | null>(null);
19
  const [impact, setImpact] = useState<number>(3);
20

21
  const { data, isLoading } = useTriggers({ limit: 5 });
22
  const linkMood = useLinkMoodToTrigger();
23

24
  const triggers = data?.entries ?? [];
25

26
  const handleSelectTrigger = (trigger: Trigger) => {
27
    setSelectedTrigger(trigger);
28
    setFlowState('PICK_IMPACT');
29
  };
30

31
  const handleSaveLink = async () => {
32
    if (!selectedTrigger || !moodId) return;
33
    await linkMood.mutateAsync({
34
      triggerId: String(selectedTrigger.id),
35
      moodId,
36
      perceivedImpact: impact,
37
    });
38
    router.back();
39
  };
40

41
  if (flowState === 'PICK_TRIGGER') {
42
    return (
43
      <View style={styles.container}>
44
        <View style={styles.header}>
45
          <Text style={styles.title}>Algo influenciou esse humor?</Text>
46
          <Text style={styles.subtitle}>
47
            Selecione um gatilho recente para vincular
48
          </Text>
49
        </View>
50

51
        <ScrollView contentContainerStyle={styles.scrollContent} showsVerticalScrollIndicator={false}>
52
          {isLoading && <ActivityIndicator style={{ marginTop: 20 }} />}
53

54
          {!isLoading && triggers.length === 0 && (
55
            <Text style={styles.emptyText}>Nenhum gatilho recente</Text>
56
          )}
57

58
          {triggers.map((trigger) => {
59
            const cat = getTriggerCategory(trigger.category);
60
            return (
61
              <TouchableOpacity
62
                key={trigger.id}
63
                style={styles.triggerCard}
64
                activeOpacity={0.7}
65
                onPress={() => handleSelectTrigger(trigger)}
66
              >
67
                <View style={[styles.triggerIcon, { backgroundColor: cat.iconBackground }]}>
68
                  <MaterialIcons name={cat.icon} size={18} color={cat.color} />
69
                </View>
70
                <View style={styles.triggerText}>
71
                  <Text style={styles.triggerCategory}>{cat.label}</Text>
72
                  {trigger.comment ? (
73
                    <Text style={styles.triggerComment} numberOfLines={1}>{trigger.comment}</Text>
74
                  ) : null}
75
                </View>
76
                <Ionicons name="chevron-forward" size={16} color={Colors.light.disabled} />
77
              </TouchableOpacity>
78
            );
79
          })}
80

81
          <Button title="Pular" variant="ghost" onPress={() => router.back()} />
82
        </ScrollView>
83
      </View>
84
    );
85
  }
86

87
  // PICK_IMPACT
88
  const cat = selectedTrigger ? getTriggerCategory(selectedTrigger.category) : null;
89
  return (
90
    <View style={styles.container}>
91
      <View style={styles.header}>
92
        <Text style={styles.title}>Qual foi o impacto?</Text>
93
        <Text style={styles.subtitle}>De 1 (leve) a 5 (muito forte)</Text>
94
      </View>
95

96
      {selectedTrigger && cat && (
97
        <View style={styles.selectedTrigger}>
98
          <View style={[styles.triggerIcon, { backgroundColor: cat.iconBackground }]}>
99
            <MaterialIcons name={cat.icon} size={18} color={cat.color} />
100
          </View>
101
          <Text style={styles.selectedTriggerLabel}>{cat.label}</Text>
102
        </View>
103
      )}
104

105
      <View style={styles.impactRow}>
106
        {[1, 2, 3, 4, 5].map((v) => (
107
          <TouchableOpacity
108
            key={v}
109
            style={[styles.impactDot, impact === v && styles.impactDotActive]}
110
            activeOpacity={0.7}
111
            onPress={() => setImpact(v)}
112
          >
113
            <Text style={[styles.impactLabel, impact === v && styles.impactLabelActive]}>{v}</Text>
114
          </TouchableOpacity>
115
        ))}
116
      </View>
117

118
      <Button
119
        title="Vincular"
120
        onPress={handleSaveLink}
121
        loading={linkMood.isPending}
122
        style={{ marginTop: 8 }}
123
      />
124
      <Button
125
        title="Voltar"
126
        variant="ghost"
127
        onPress={() => setFlowState('PICK_TRIGGER')}
128
      />
129
    </View>
130
  );
131
}
132

133
const styles = StyleSheet.create({
134
  container: {
135
    flex: 1,
136
    paddingHorizontal: Spacing.containerPadding,
137
    paddingTop: 24,
138
    paddingBottom: 36,
139
    gap: 16,
140
  },
141
  header: { gap: 6 },
142
  title: { ...Typography.headlineMd },
143
  subtitle: { ...Typography.bodyMd, color: Colors.light.textSecondary },
144
  scrollContent: { gap: 10, paddingBottom: 20 },
145
  emptyText: { ...Typography.bodyMd, color: Colors.light.textSecondary, textAlign: 'center', marginTop: 20 },
146
  triggerCard: {
147
    flexDirection: 'row',
148
    alignItems: 'center',
149
    backgroundColor: '#fff',
150
    borderRadius: BorderRadius.lg,
151
    padding: Spacing.cardGap,
152
    borderWidth: 1,
153
    borderColor: Colors.light.divider,
154
    gap: 12,
155
  },
156
  triggerIcon: {
157
    width: 36,
158
    height: 36,
159
    borderRadius: BorderRadius.md,
160
    alignItems: 'center',
161
    justifyContent: 'center',
162
  },
163
  triggerText: { flex: 1, gap: 2 },
164
  triggerCategory: { ...Typography.bodyMd, fontWeight: '600' },
165
  triggerComment: { ...Typography.labelSm, color: Colors.light.textSecondary },
166
  selectedTrigger: {
167
    flexDirection: 'row',
168
    alignItems: 'center',
169
    gap: 12,
170
    padding: Spacing.cardGap,
171
    backgroundColor: Colors.light.surface,
172
    borderRadius: BorderRadius.lg,
173
    borderWidth: 1,
174
    borderColor: Colors.light.divider,
175
  },
176
  selectedTriggerLabel: { ...Typography.bodyMd, fontWeight: '600' },
177
  impactRow: {
178
    flexDirection: 'row',
179
    justifyContent: 'center',
180
    gap: 12,
181
    marginVertical: 8,
182
  },
183
  impactDot: {
184
    width: 48,
185
    height: 48,
186
    borderRadius: 24,
187
    borderWidth: 2,
188
    borderColor: Colors.light.divider,
189
    alignItems: 'center',
190
    justifyContent: 'center',
191
    backgroundColor: '#fff',
192
  },
193
  impactDotActive: {
194
    borderColor: Colors.light.tint,
195
    backgroundColor: Colors.light.tint + '1A',
196
  },
197
  impactLabel: { fontSize: 18, fontWeight: '600', color: Colors.light.textSecondary },
198
  impactLabelActive: { color: Colors.light.text },
199
});