eletrotupi / tcc/ frontend/components/ui/ConfirmModal.tsx254c7850308a7fd9fe9233bdd97657ada3d3eab8
3.6 KB | 158 lines Raw
1
import React from 'react';
2
import { Modal, Pressable, StyleSheet, View } from 'react-native';
3

4
import { Button } from '@/components/ui/Button';
5
import { Text } from '@/components/ui/Text';
6
import {
7
  BorderRadius,
8
  Colors,
9
  Spacing,
10
  Shadows,
11
  Typography,
12
} from '@/constants/theme';
13

14
interface ConfirmModalProps {
15
  visible: boolean;
16
  title: string;
17
  message?: string;
18
  detail?: string;
19
  confirmLabel?: string;
20
  cancelLabel?: string;
21
  destructive?: boolean;
22
  loading?: boolean;
23
  onConfirm: () => void;
24
  onCancel: () => void;
25
  testID?: string;
26
}
27

28
export const ConfirmModal: React.FC<ConfirmModalProps> = ({
29
  visible,
30
  title,
31
  message,
32
  detail,
33
  confirmLabel = 'Confirmar',
34
  cancelLabel = 'Cancelar',
35
  destructive = false,
36
  loading = false,
37
  onConfirm,
38
  onCancel,
39
  testID = 'confirm-modal',
40
}) => {
41
  const dismiss = () => {
42
    if (!loading) {
43
      onCancel();
44
    }
45
  };
46

47
  return (
48
    <Modal
49
      visible={visible}
50
      transparent
51
      animationType="fade"
52
      statusBarTranslucent
53
      onRequestClose={dismiss}
54
    >
55
      <View style={styles.overlay}>
56
        <Pressable
57
          style={StyleSheet.absoluteFill}
58
          onPress={dismiss}
59
          testID={`${testID}-overlay`}
60
        />
61

62
        <View style={styles.cardContainer} pointerEvents="box-none">
63
          <Pressable
64
            style={styles.card}
65
            accessibilityViewIsModal
66
            testID={testID}
67
          >
68
            <Text style={styles.title}>{title}</Text>
69

70
            {message ? <Text style={styles.message}>{message}</Text> : null}
71

72
            {detail ? (
73
              <View style={styles.detail}>
74
                <Text style={styles.detailText}>{detail}</Text>
75
              </View>
76
            ) : null}
77

78
            <View style={styles.footer}>
79
              <Button
80
                title={cancelLabel}
81
                variant="ghost"
82
                style={styles.footerButton}
83
                disabled={loading}
84
                onPress={onCancel}
85
                testID={`${testID}-cancel`}
86
              />
87
              <Button
88
                title={confirmLabel}
89
                variant={destructive ? 'danger' : 'primary'}
90
                style={styles.footerButton}
91
                loading={loading}
92
                onPress={onConfirm}
93
                testID={`${testID}-confirm`}
94
              />
95
            </View>
96
          </Pressable>
97
        </View>
98
      </View>
99
    </Modal>
100
  );
101
};
102

103
const OVERLAY_BACKGROUND = 'rgba(15, 23, 42, 0.55)';
104

105
const styles = StyleSheet.create({
106
  overlay: {
107
    flex: 1,
108
    backgroundColor: OVERLAY_BACKGROUND,
109
  },
110
  cardContainer: {
111
    flex: 1,
112
    width: '100%',
113
    alignItems: 'center',
114
    justifyContent: 'center',
115
    padding: Spacing.containerPadding * 1.5,
116
  },
117
  card: {
118
    width: '100%',
119
    maxWidth: 400,
120
    backgroundColor: Colors.light.surface,
121
    borderRadius: BorderRadius.xl,
122
    borderWidth: 1,
123
    borderColor: Colors.light.cardBorder,
124
    padding: Spacing.containerPadding + 4,
125
    ...Shadows.md,
126
  },
127
  title: {
128
    ...Typography.headlineMd,
129
    color: Colors.light.text,
130
    textAlign: 'center',
131
  },
132
  message: {
133
    ...Typography.bodyMd,
134
    color: Colors.light.textSecondary,
135
    textAlign: 'center',
136
    marginTop: Spacing.inlineGapSm,
137
  },
138
  detail: {
139
    marginTop: Spacing.cardGap,
140
    backgroundColor: Colors.light.accentBlue,
141
    borderRadius: BorderRadius.md,
142
    paddingVertical: Spacing.inlineGapSm,
143
    paddingHorizontal: Spacing.cardGap,
144
  },
145
  detailText: {
146
    ...Typography.bodyLg,
147
    color: Colors.light.text,
148
    textAlign: 'center',
149
  },
150
  footer: {
151
    flexDirection: 'row',
152
    gap: Spacing.cardGap,
153
    marginTop: Spacing.containerPadding,
154
  },
155
  footerButton: {
156
    flex: 1,
157
  },
158
});