# React Form Integration - Usage Example

## Overview

This document shows how to set up a JOE page with a React-powered form using JSON form definitions.

## Setup Steps

### 1. Create JSON Form Definition Include

1. In JOE, go to **Includes** schema
2. Create a new include:
   - **Name**: "Harmonious Wellness Form Definition"
   - **Filetype**: `json`
   - **Content**: Paste your `form-qs.json` content
   - **Fill Template**: `false` (or `true` if you want to use `${this.}` variables)
3. Save and note the `_id` of the include

### 2. Create JOE Form Record

1. Go to **Forms** schema
2. Create a new form:
   - **Name**: "Harmonious Wellness Health Questionnaire"
   - **Save Submission**: `true`
   - **Meta** (optional): Add `json_definition_include: "{include_id}"` if you want to link it
3. Save and note the `_id` of the form

### 3. Create React Form JS Include (if not already created)

1. Go to **Includes** schema
2. Create a new include:
   - **Name**: "JOE React Form Renderer"
   - **Filetype**: `js`
   - **Content**: Copy content from `js/joe-react-form.js`
3. Save and note the `_id` of the include

### 4. Create JOE Page

1. Go to **Pages** schema
2. Create a new page:
   - **Name**: "Health Questionnaire"
   - **Site**: Select your site
   - **Path**: `/health-questionnaire` (or your desired path)
   - **Content Type**: `code` (or `module` for dynamic generation - see examples below)
   - **Form**: Select the form you created in step 2
   - **Includes**: 
     - Add the React Form JS include from step 3
     - Add the JSON Form Definition include from step 1 (optional - formDefinition plugin can find it automatically)
   - **Content**: Use the template below
   - **Layout**: Select a layout (or create one with minimal structure)

**Note:** When using `${INCLUDES}` in your page content, JOE will automatically generate `<script>` and `<link>` tags for all JS and CSS includes you add here. The JSON include is accessed via the formDefinition API endpoint, not as a direct include.

### 5. Page Content Template

**Option A: Using Code Content Type with Template Variables (Recommended)**

Set `content_type: 'code'` and use JOE template variables:

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>${this.PAGE.name}</title>
    
    <!-- Tailwind CSS (for styling) - Optional -->
    <script src="https://cdn.tailwindcss.com"></script>
    
    <!-- React from CDN - MUST load before ${INCLUDES} (which contains joe-react-form.js) -->
    <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
    
    <!-- JOE automatically includes all JS/CSS from page.includes here -->
    <!-- Note: joe-react-form.js will wait for React if needed, but loading React first is recommended -->
    ${INCLUDES}
</head>
<body>
    <div id="react-form-root"></div>
    <script>
        // Wait for joeReactForm to be available (script may still be loading)
        function initForm() {
            if (typeof joeReactForm !== 'undefined') {
                joeReactForm.init({
                    rootId: 'react-form-root',
                    formDefinitionUrl: '/API/plugin/formBuilder/definition?formid=${this.PAGE.form}&pageid=${this.PAGE._id}',
                    formId: '${this.PAGE.form}'
                });
            } else {
                // If not ready, wait for DOMContentLoaded or check again shortly
                if (document.readyState === 'loading') {
                    document.addEventListener('DOMContentLoaded', initForm);
                } else {
                    setTimeout(initForm, 50);
                }
            }
        }
        initForm();
    </script>
</body>
</html>
```

**Benefits:**
- `${INCLUDES}` automatically includes all JS/CSS from page's includes array
- `${this.PAGE.form}` and `${this.PAGE._id}` automatically use linked form and page IDs
- No hardcoded IDs to maintain!

**Option B: Using Module Content Type**

Set `content_type: 'module'` - see the "Alternative: Using Module Content Type" section below.

### Alternative: Using Module Content Type (Recommended)

You can use `content_type: 'module'` to generate HTML dynamically using JOE's template patterns:

```javascript
module.exports = function(content) {
    var page = content.PAGE;
    var form = page.form ? JOE.Cache.findByID('form', page.form) : null;
    
    if (!form) {
        return '<div>Error: No form linked to this page</div>';
    }
    
    // Use formDefinition plugin to auto-find JSON include from page
    // This will find the JSON include from page.includes automatically
    var formDefUrl = '/API/plugin/formBuilder/definition?formid=' + form._id + '&pageid=' + page._id;
    
    return `<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>${page.name}</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
    ${content.INCLUDES}
</head>
<body>
    <div id="react-form-root"></div>
    <script>
        // Wait for joeReactForm to be available (script may still be loading)
        function initForm() {
            if (typeof joeReactForm !== 'undefined') {
                joeReactForm.init({
                    rootId: 'react-form-root',
                    formDefinitionUrl: '${formDefUrl}',
                    formId: '${form._id}'
                });
            } else {
                if (document.readyState === 'loading') {
                    document.addEventListener('DOMContentLoaded', initForm);
                } else {
                    setTimeout(initForm, 50);
                }
            }
        }
        initForm();
    </script>
</body>
</html>`;
};
```

**Key improvements:**
- Uses `${content.INCLUDES}` - automatically includes all JS/CSS from page's includes array
- Uses `formBuilder.definition` endpoint with `pageid` - automatically finds JSON include from page
- No need to manually specify include IDs

### Alternative: Using Code Content Type with Template Variables

You can also use `content_type: 'code'` with JOE template variables:

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>${this.PAGE.name}</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
    ${INCLUDES}
</head>
<body>
    <div id="react-form-root"></div>
    <script>
        // Wait for joeReactForm to be available (script may still be loading)
        function initForm() {
            if (typeof joeReactForm !== 'undefined') {
                joeReactForm.init({
                    rootId: 'react-form-root',
                    formDefinitionUrl: '/API/plugin/formBuilder/definition?formid=${this.PAGE.form}&pageid=${this.PAGE._id}',
                    formId: '${this.PAGE.form}'
                });
            } else {
                if (document.readyState === 'loading') {
                    document.addEventListener('DOMContentLoaded', initForm);
                } else {
                    setTimeout(initForm, 50);
                }
            }
        }
        initForm();
    </script>
</body>
</html>
```

This automatically:
- Uses `${INCLUDES}` to inject all page includes (JS/CSS)
- Uses `${this.PAGE.form}` and `${this.PAGE._id}` to pass form and page IDs
- No hardcoded IDs needed!

## API Endpoints

### Get Form Definition

```
GET /API/plugin/formBuilder/definition?include_id={include_id}
GET /API/plugin/formBuilder/definition?formid={form_id}&field=json_definition_include
```

Returns: JSON form definition (form-qs.json format)

### Submit Form

```
POST /API/plugin/formBuilder/submission
Content-Type: application/json

{
    "formid": "{form_id}",
    "submission": {
        "first_name": "John",
        "last_name": "Doe",
        ...
    }
}
```

Returns: Submission confirmation or error

## How It Works

1. **Page loads** → Includes React CDN and form renderer JS
2. **Form renderer initializes** → Fetches JSON form definition from include
3. **React renders form** → Based on JSON structure (sections, fields, visibility rules)
4. **User fills form** → React manages state and conditional visibility
5. **User submits** → Data sent to `/API/plugin/formBuilder/submission`
6. **JOE saves submission** → Creates `submission` record linked to form

## Customization

### Styling

The form uses Tailwind CSS classes. You can:
- Include Tailwind CDN (as shown above)
- Add custom CSS via include
- Modify classes in `joe-react-form.js`

### Form Definition Template Variables

If you enable `fillTemplate` on the JSON include, you can use variables like:
```json
{
    "formName": "${this.SITE.name} - Health Questionnaire",
    "version": "${this.WEBCONFIG.version}"
}
```

### Form Callbacks

The JOE form record supports:
- **Callback**: Client-side function called after submission
- **Server Action**: Server-side function called during submission
- **Validate**: Client-side validation function

These can be added to the form record and will be executed as configured.

## Troubleshooting

### Form not loading
- Check browser console for errors
- Verify all include IDs are correct
- Ensure React CDN is loading (check Network tab)

### Submission errors
- Verify form ID is correct
- Check that form has `save_submission: true`
- Check server logs for submission errors

### Styling issues
- Ensure Tailwind CSS is loaded (or adjust classes)
- Check that Tailwind CDN version supports all classes used
