# Modal Component

Modal component tương tự như Modal của Ant Design, được tạo cho React Native/Expo.

## Cài đặt

Component này sử dụng `@expo/vector-icons` cho các icon. Đảm bảo bạn đã cài đặt:

```bash
npx expo install @expo/vector-icons
```

## Import

```tsx
import Modal from "@/components/ui/modal";
```

## Các tính năng chính

### 1. Basic Modal

```tsx
import React, { useState } from "react";
import { View, Text, Button } from "react-native";
import Modal from "@/components/ui/modal";

export default function BasicExample() {
  const [open, setOpen] = useState(false);

  return (
    <View>
      <Button title="Open Modal" onPress={() => setOpen(true)} />

      <Modal
        open={open}
        title="Basic Modal"
        onOk={() => {
          console.log("OK clicked");
          setOpen(false);
        }}
        onCancel={() => setOpen(false)}
      >
        <Text>Some contents...</Text>
        <Text>Some contents...</Text>
        <Text>Some contents...</Text>
      </Modal>
    </View>
  );
}
```

### 2. Async Close (với confirmLoading)

```tsx
import React, { useState } from "react";
import { View, Text, Button } from "react-native";
import Modal from "@/components/ui/modal";

export default function AsyncExample() {
  const [open, setOpen] = useState(false);
  const [loading, setLoading] = useState(false);

  const handleOk = async () => {
    setLoading(true);
    // Giả lập API call
    await new Promise((resolve) => setTimeout(resolve, 2000));
    setLoading(false);
    setOpen(false);
  };

  return (
    <View>
      <Button title="Open Modal" onPress={() => setOpen(true)} />

      <Modal
        open={open}
        title="Async Modal"
        confirmLoading={loading}
        onOk={handleOk}
        onCancel={() => setOpen(false)}
      >
        <Text>Modal will be closed after 2 seconds when you click OK.</Text>
      </Modal>
    </View>
  );
}
```

### 3. Customized Footer

```tsx
import React, { useState } from "react";
import { View, Text, Button, TouchableOpacity, StyleSheet } from "react-native";
import Modal from "@/components/ui/modal";

export default function CustomFooterExample() {
  const [open, setOpen] = useState(false);

  return (
    <View>
      <Button title="Open Modal" onPress={() => setOpen(true)} />

      <Modal
        open={open}
        title="Custom Footer Modal"
        onCancel={() => setOpen(false)}
        footer={
          <View style={styles.customFooter}>
            <TouchableOpacity
              style={styles.customButton}
              onPress={() => setOpen(false)}
            >
              <Text style={styles.buttonText}>Return</Text>
            </TouchableOpacity>
            <TouchableOpacity
              style={[styles.customButton, styles.submitButton]}
              onPress={() => {
                console.log("Submit");
                setOpen(false);
              }}
            >
              <Text style={[styles.buttonText, styles.submitText]}>Submit</Text>
            </TouchableOpacity>
          </View>
        }
      >
        <Text>Custom footer buttons</Text>
      </Modal>
    </View>
  );
}

const styles = StyleSheet.create({
  customFooter: {
    flexDirection: "row",
    gap: 8,
  },
  customButton: {
    paddingHorizontal: 16,
    paddingVertical: 8,
    borderRadius: 6,
    borderWidth: 1,
    borderColor: "#d9d9d9",
  },
  submitButton: {
    backgroundColor: "#1890ff",
    borderColor: "#1890ff",
  },
  buttonText: {
    fontSize: 14,
    color: "#000",
  },
  submitText: {
    color: "#fff",
  },
});
```

### 4. No Footer

```tsx
<Modal
  open={open}
  title="Modal Without Footer"
  footer={null}
  onCancel={() => setOpen(false)}
>
  <Text>Modal content without footer buttons</Text>
</Modal>
```

### 5. Centered Modal

```tsx
<Modal
  open={open}
  title="Centered Modal"
  centered
  onOk={() => setOpen(false)}
  onCancel={() => setOpen(false)}
>
  <Text>This modal is centered on the screen</Text>
</Modal>
```

### 6. Custom Width

```tsx
<Modal
  open={open}
  title="Custom Width Modal"
  width={700}
  onOk={() => setOpen(false)}
  onCancel={() => setOpen(false)}
>
  <Text>This modal has custom width</Text>
</Modal>
```

### 7. Confirm Modal với useModal Hook

**Đây là cách khuyến nghị sử dụng trong React Native để có context đầy đủ:**

```tsx
import React from "react";
import { View, Button } from "react-native";
import Modal from "@/components/ui/modal";

export default function HookExample() {
  const [modal, contextHolder] = Modal.useModal();

  const showConfirm = () => {
    modal.confirm({
      title: "Do you want to delete these items?",
      content:
        "When clicked the OK button, this dialog will be closed after 1 second",
      onOk: async () => {
        await new Promise((resolve) => setTimeout(resolve, 1000));
        console.log("OK");
      },
      onCancel: () => {
        console.log("Cancel");
      },
    });
  };

  const showInfo = () => {
    modal.info({
      title: "This is a notification message",
      content: "Some additional information...",
    });
  };

  const showSuccess = () => {
    modal.success({
      title: "Success",
      content: "Operation completed successfully!",
    });
  };

  const showError = () => {
    modal.error({
      title: "Error",
      content: "Something went wrong!",
    });
  };

  const showWarning = () => {
    modal.warning({
      title: "Warning",
      content: "This is a warning message!",
    });
  };

  return (
    <View style={{ padding: 20, gap: 10 }}>
      {/* contextHolder phải được đặt trong component */}
      {contextHolder}

      <Button title="Confirm" onPress={showConfirm} />
      <Button title="Info" onPress={showInfo} />
      <Button title="Success" onPress={showSuccess} />
      <Button title="Error" onPress={showError} />
      <Button title="Warning" onPress={showWarning} />
    </View>
  );
}
```

### 8. Update Modal Instance

```tsx
import React from "react";
import { View, Button } from "react-native";
import Modal from "@/components/ui/modal";

export default function UpdateExample() {
  const [modal, contextHolder] = Modal.useModal();

  const showModal = () => {
    const instance = modal.success({
      title: "Loading...",
      content: "Please wait...",
    });

    // Update after 2 seconds
    setTimeout(() => {
      instance.update({
        title: "Success!",
        content: "Operation completed successfully!",
      });
    }, 2000);

    // Close after 4 seconds
    setTimeout(() => {
      instance.destroy();
    }, 4000);
  };

  return (
    <View>
      {contextHolder}
      <Button title="Show Updating Modal" onPress={showModal} />
    </View>
  );
}
```

## API

### Modal Props

| Prop            | Type                          | Default   | Description                                                  |
| --------------- | ----------------------------- | --------- | ------------------------------------------------------------ |
| open            | boolean                       | false     | Whether the modal dialog is visible or not                   |
| title           | ReactNode                     | -         | The modal dialog's title                                     |
| closable        | boolean                       | true      | Whether a close (x) button is visible on top right or not    |
| closeIcon       | ReactNode                     | -         | Custom close icon                                            |
| maskClosable    | boolean                       | true      | Whether to close the modal dialog when the mask is clicked   |
| centered        | boolean                       | false     | Centered Modal                                               |
| width           | number \| string              | 520       | Width of the modal dialog                                    |
| confirmLoading  | boolean                       | false     | Whether to apply loading visual effect for OK button         |
| okText          | string                        | 'OK'      | Text of the OK button                                        |
| cancelText      | string                        | 'Cancel'  | Text of the Cancel button                                    |
| okType          | 'primary' \| 'default'        | 'primary' | Button type of the OK button                                 |
| footer          | ReactNode \| null             | -         | Footer content, set as footer={null} to hide default buttons |
| mask            | boolean                       | true      | Whether show mask or not                                     |
| zIndex          | number                        | 1000      | The z-index of the Modal                                     |
| onOk            | (e?) => void \| Promise<void> | -         | Callback when clicking OK button                             |
| onCancel        | (e?) => void                  | -         | Callback when clicking cancel button or close icon           |
| afterOpenChange | (open: boolean) => void       | -         | Callback when animation ends                                 |
| afterClose      | () => void                    | -         | Callback when modal is closed completely                     |
| destroyOnClose  | boolean                       | false     | Whether to unmount child components on close                 |
| keyboard        | boolean                       | true      | Whether support press back button to close (Android)         |

### Modal.useModal()

Khi bạn cần sử dụng Context, bạn có thể dùng `Modal.useModal()` để tạo `contextHolder` và chèn vào children. Modal được tạo bởi hooks sẽ có tất cả context nơi `contextHolder` được đặt.

**Returns:** `[modalMethods, contextHolder]`

- `modalMethods`: Object chứa các methods

  - `info(config)`: Show info modal
  - `success(config)`: Show success modal
  - `error(config)`: Show error modal
  - `warning(config)`: Show warning modal
  - `confirm(config)`: Show confirm modal

- `contextHolder`: React element cần được render trong component tree

### Modal Methods Config

| Prop       | Type                                                     | Default   | Description                   |
| ---------- | -------------------------------------------------------- | --------- | ----------------------------- |
| type       | 'info' \| 'success' \| 'error' \| 'warning' \| 'confirm' | 'confirm' | Type of the modal             |
| title      | ReactNode                                                | -         | Title                         |
| content    | ReactNode                                                | -         | Content                       |
| icon       | ReactNode                                                | -         | Custom icon                   |
| okText     | string                                                   | 'OK'      | Text of the OK button         |
| cancelText | string                                                   | 'Cancel'  | Text of the Cancel button     |
| onOk       | (e?) => void \| Promise<void>                            | -         | Callback when clicking OK     |
| onCancel   | (e?) => void                                             | -         | Callback when clicking Cancel |

### Modal Instance

Modal instance được trả về bởi `Modal.useModal()`:

```tsx
interface ModalInstance {
  destroy: () => void;
  update: (config: ConfirmModalProps) => void;
}
```

## Lưu ý

1. **React Native Limitations**: Các static methods như `Modal.info()`, `Modal.confirm()` gọi trực tiếp (không qua hook) không được hỗ trợ đầy đủ trong React Native do không thể render imperatively. Hãy sử dụng `Modal.useModal()` hook thay thế.

2. **Context Support**: Khi cần sử dụng Context (như Redux, Theme Context), bắt buộc phải dùng `Modal.useModal()` hook và đặt `contextHolder` trong component tree.

3. **Animation**: Modal sử dụng React Native's built-in Modal với `animationType="fade"`.

4. **Icons**: Component sử dụng `@expo/vector-icons` (Ionicons). Đảm bảo đã cài đặt package này.

5. **Keyboard**: Prop `keyboard` trong React Native chỉ hoạt động với nút back của Android (không có ESC key như web).

## So sánh với Ant Design Modal

| Feature                     | Ant Design (Web) | This Component (RN)         |
| --------------------------- | ---------------- | --------------------------- |
| Basic Modal                 | ✅               | ✅                          |
| Centered                    | ✅               | ✅                          |
| Custom Footer               | ✅               | ✅                          |
| Confirm Dialog              | ✅               | ✅ (via useModal)           |
| Info/Success/Error/Warning  | ✅               | ✅ (via useModal)           |
| Async close                 | ✅               | ✅                          |
| Custom width                | ✅               | ✅                          |
| Mask closable               | ✅               | ✅                          |
| Keyboard close              | ✅ (ESC)         | ✅ (Back button on Android) |
| Static methods without hook | ✅               | ⚠️ (Limited support)        |
| useModal hook               | ✅               | ✅ (Recommended)            |
| Draggable                   | ✅               | ❌ (Not applicable)         |
| destroyAll()                | ✅               | ❌                          |

## License

MIT
