# Crowe Pinboard

An advanced pinboard system for RedM servers that allows players to share images and create custom posters at various locations around the map.

## 📋 Features

* **🏃‍♂️ Interactive Pinboards**: Place pinboards at custom locations around the map
* **🔐 Permission System**: Control who can view, add, or remove posts per board
* **🤠 VORP Integration**: Full integration with VORP Core for character data
* **💾 Persistent Storage**: Posts are saved to database and persist through server restarts
* **📢 Discord Webhooks**: Optional Discord integration for post notifications
* **🛠️ Admin Tools**: Comprehensive admin commands for managing posts and boards
* **📱 Responsive UI**: Modern HTML/CSS/JavaScript interface with light theme
* **⏰ Post Expiration**: Automatic cleanup of old posts with configurable durations
* **🖼️ Image Support**: Support for image posts with URL validation
* **🎨 Poster Creator**: Advanced poster creation tool with builtin and custom templates
* **📥 Import Templates**: Upload custom template images for unique posters
* **🌐 Multi-language Support**: Configurable language system
* **🗺️ Map Blips**: Optional map markers for pinboard locations with customizable colors
* **⚔️ Combat Auto-close**: UI closes automatically during combat
* **🖱️ Enhanced NUI Focus**: Robust cursor and focus management for smooth UI interaction
* **📊 Real-time Updates**: Posts appear immediately with automatic refresh system
* **🎯 Camera Integration**: Smooth camera transitions to pinboard locations
* **💰 Posting Fee System**: Configurable fees with job-based reductions and free posting
* **🖼️ Image Preview**: See image previews before posting to verify links and layout
* **⏰ Expiration Timer Control**: Option to hide countdown timers on posters
* **🔐 Job-Based Permissions**: Separate job and group permissions for post removal and bulk posting

## 📋 Post Types

The system currently supports two main post types:

### Image Posts

* **URL-based**: Enter any valid image URL (https\://...)
* **Validation**: Automatic URL format and accessibility checking
* **Expiration**: Configurable expiration time (default: 24 hours)
* **Preview**: See your image before posting with real-time preview
* **Fee Display**: Shows posting cost before submission

### Poster Posts

* **Template-based**: Choose from builtin templates or import custom ones
* **Text Overlays**: Add unlimited text boxes with custom styling
* **Rich Editor**: Full-featured editor with real-time preview
* **Expiration**: Configurable expiration time (default: 24 hours)
* **Customization**: Full control over text positioning, fonts, and colors

> **Note**: Text posts are configured in the backend but not currently implemented in the UI. The system focuses on visual content through images and custom posters.

## 🚀 Installation

### Prerequisites

* RedM Server with Lua 5.4 support
* [VORP Core](https://github.com/VORPCORE/vorp-core-lua) (latest version)
* [oxmysql](https://github.com/overextended/oxmysql) (for database storage)

### Step-by-Step Installation

1. **Download the latest release** from the GitHub releases page
2. **Extract the archive** to your server's `resources` folder
3. **Rename the folder** to `crowe_pinboard` if needed
4. **Configure the resource**:

   ```bash
   cp config.demo.lua config/config.lua
   # Edit config/config.lua with your preferred settings
   ```
5. **Add to server.cfg**:

   ```
   ensure oxmysql
   ensure vorp_core
   ensure crowe_pinboard
   ```
6. **Restart your server** or use `refresh` then `ensure crowe_pinboard`

### Database Setup

The resource will automatically create the necessary database table on first run if `Config.UseDatabase = true`.

## 🌐 Multi-Language Support

The resource supports multiple languages through configurable language files. Currently available languages:

* **English** (`en`) - Default language
* **German** (`de`) - German translations

### Language Configuration

```lua
Config.Language = 'de'  -- Set to 'en' for English, 'de' for German
```

### Adding New Languages

To add a new language:

1. **Create a new language file** in the `lang/` folder (e.g., `lang/fr.lua`)
2. **Follow the existing structure** from `lang/en.lua`
3. **Add the file to `fxmanifest.lua`** in the `shared_scripts` section
4. **Update `escrow_ignore`** to include the new language file
5. **Set `Config.Language`** to your new language code

Example language file structure:

```lua
Lang = {}
Lang['fr'] = {
    ['open_pinboard'] = 'Ouvrir le tableau d\'affichage',
    ['post_created'] = 'Message créé avec succès!',
    -- ... more translations
}
```

## ⚙️ Configuration

The main configuration file is located at `config/config.lua`. Key settings include:

### Basic Settings

```lua
Config.InteractionRadius = 3.0    -- Distance to show interaction prompt
Config.MaxPostsPerBoard = 8       -- Maximum posts per board
Config.AllowImagePosts = true     -- Enable image posts
Config.CloseOnCombat = true       -- Auto-close UI during combat

-- Expiration settings (in hours - 0 = no expiration)
Config.DefaultPostExpiration = 7 * 24     -- 7 days for default posts
Config.PosterExpiration = 24              -- 24 hours for posters
Config.ImagePostExpiration = 24           -- 24 hours for image posts

-- Fee and permission settings
Config.RemovePostGroups = {"admin", "moderator"}     -- Groups that can remove any posts
Config.RemovePostJobs = {"sheriff", "marshal"}       -- Jobs that can remove any posts
```

### Pinboard Locations

Define your pinboard locations in the `Config.Pinboards` table:

```lua
{
    id = 1,
    name = "Valentine Sheriff's Office",
    group = "law_enforcement",
    location = {x = -275.0, y = 800.0, z = 119.0},
    style = "indoor",
    show_blip = true,
    permissions = {
        view = {},
        add = {"sheriff", "deputy"},
        remove = {"sheriff", "deputy", "admin"}
    }
}
```

### Discord Integration

Enable Discord webhooks for post notifications:

```lua
Config.DiscordWebhook = {
    enabled = true,
    global_url = 'https://discord.com/api/webhooks/YOUR_WEBHOOK_URL',
    anonymous_mode = false,
    system_user_alias = 'System'
}
```

### Job-Based Fee Reductions

Configure job-specific posting fee reductions:

```lua
Config.JobFeeReductions = {
    free_posting_jobs = {"sheriff", "marshal"},           -- Jobs that post for free
    reduced_fee_jobs = {"deputy", "constable"},            -- Jobs with reduced fees
    specific_reductions = {                                -- Custom fee amounts per job
        ["deputy"] = 5,                                    -- Deputy pays $5 instead of $10
        ["constable"] = 3                                  -- Constable pays $3 instead of $10
    }
}
```

## 🎮 Usage

### For Players

#### Basic Posting

1. Walk up to any pinboard location (look for the interaction prompt)
2. Press **G** (default) to open the pinboard interface
3. View existing posts by scrolling through the pinboard
4. Click the **+** button to create a new post
5. Choose between image posts or poster creation

#### Image Posts

1. Select **"Image URL"** option
2. Enter a valid image URL (https\://...)
3. Click **"Add Post"** to publish

#### Poster Creation

1. Select **"Create Poster"** option
2. Choose from builtin templates or import a custom template:
   * **Builtin Templates**: Click on template1, template2, or template3
   * **Custom Template**: Enter image URL and click "Import Template"
3. Click **"Open Editor"** to access the poster editor
4. Add text boxes with custom positioning, fonts, colors, and styling
5. Use the editor sidebar to customize:
   * **Text Content**: Type your message with manual line breaks (Enter key)
   * **Position**: Drag sliders to position text precisely (X/Y coordinates)
   * **Font Options**: Choose from system font families and sizes (8-48px)
   * **Styling**: Apply bold, italic, underline, strikethrough
   * **Alignment**: Left, center, or right align text
   * **Colors**: Use the color picker for custom text colors
6. Click **"Save Poster"** to create and submit your poster

### For Administrators

Use these console commands for management:

* `/pinboard clear` - Remove all posts from all boards
* `/pinboard clear [board_id]` - Remove all posts from a specific board

## 📋 Permissions

The resource uses a flexible permission system based on jobs and groups:

### Global Permissions

* `Config.AdminGroups`: Full access to all features and admin commands
* `Config.RemovePostGroups`: Can remove any posts (not just their own)

### Per-Board Permissions

Each board can have custom permissions for:

* `view`: Who can see and access the board
* `add`: Who can create new posts
* `remove`: Who can remove posts (beyond the author)

### Permission Examples

```lua
permissions = {
    view = {},                          -- Everyone can view
    add = {"sheriff", "deputy"},        -- Only law enforcement can post  
    remove = {"sheriff", "deputy", "admin"} -- Law enforcement + admins can remove
}

-- Board-specific expiration timer control
{
    id = 1,
    name = "Valentine Sheriff's Office",
    group = "law_enforcement",
    location = {x = -275.0, y = 800.0, z = 119.0},
    style = "indoor",
    show_blip = true,
    hideExpirationTimer = false,        -- Set to true to hide countdown timers
    permissions = {
        view = {},
        add = {"sheriff", "deputy"},
        remove = {"sheriff", "deputy", "admin"}
    }
}
```

## 🎨 Poster Creator Features

### Builtin Templates

* **Template 1**: Classic wanted poster style
* **Template 2**: Official document layout
* **Template 3**: Modern announcement design

### Custom Template Import

* **URL Support**: Import any image URL as a template
* **Validation**: Automatic image URL validation
* **Preview**: See your custom template before editing
* **Flexibility**: Use any image format (JPG, PNG, GIF, WebP, BMP)

### Text Editor Capabilities

* **Multiple Text Boxes**: Add unlimited text elements
* **Precise Positioning**: X/Y coordinates with percentage-based positioning (0-100%)
* **Font Variety**: Choose from system fonts (Arial, Times New Roman, Georgia, etc.)
* **Rich Styling**: Bold, italic, underline, strikethrough
* **Text Alignment**: Left, center, or right alignment
* **Color Customization**: Full color picker for text colors
* **Line Breaks**: Manual line breaks with Enter key
* **Real-time Preview**: See changes instantly as you edit
* **Font Size Range**: 8px to 48px for optimal readability
* **Responsive Design**: Text scales appropriately for different template sizes
* **Layout Stability**: Text boxes maintain position without shifting when adding more elements

## 🗂️ File Structure

```
crowe_pinboard/
├── fxmanifest.lua           # Resource manifest
├── config/
│   ├── config.lua           # Main configuration (copy from config.demo.lua)
│   └── config.demo.lua      # Demo configuration with examples
├── server/
│   ├── main.lua             # Core server logic
│   └── admin.lua            # Admin commands and tools
├── client/
│   ├── main.lua             # Client interaction logic
│   └── blips.lua            # Map blip management
├── shared/
│   └── utils.lua            # Shared utility functions
├── html/
│   ├── index.html           # UI HTML structure
│   ├── style.css            # UI styling with tan theme
│   └── main.js              # UI JavaScript logic with enhanced NUI focus
├── lang/
│   └── en.lua               # English language file
├── html/assets/
│   ├── images/              # Template images
│   │   ├── template1.png    # Wanted poster template
│   │   ├── template.png     # Official document template
│   │   └── template3.png    # Announcement template
│   └── jquery-3.6.0.min.js # jQuery library
├── README.md                # This file
└── CHANGELOG.md             # Version history
```

## 🐛 Troubleshooting

### Common Issues

**Pinboards don't appear**

* Check that VORP Core is running and loaded before Crowe Pinboard
* Verify coordinates in `Config.Pinboards` are correct
* Enable `Config.DevMode = true` to see interaction radius visually

**Database errors**

* Ensure oxmysql is installed and configured properly
* Check that your database user has CREATE and INSERT permissions
* Set `Config.UseDatabase = false` as a temporary workaround

**Permission issues**

* Verify job names match exactly with your VORP Core jobs
* Check the `permissions` table for each board
* Ensure players have the correct jobs assigned in VORP

**UI not opening**

* Check browser console for JavaScript errors (F12)
* Verify all files in the `html/` folder exist
* Try clearing your FiveM cache

**Cursor disappears in UI**

* The system now includes enhanced NUI focus management
* Cursor should remain visible throughout all interactions
* If issues persist, check console for focus-related errors

**Poster posts don't appear immediately**

* The system now includes automatic post refresh
* Posters should appear within 3 seconds of creation
* Check console for post creation debugging information

**Posts not syncing between players**

* The system includes real-time updates and automatic refresh
* Check server console for post creation events
* Verify database connectivity and permissions

## 🔧 Development

### Adding New Languages

1. Copy `lang/en.lua` to `lang/[language_code].lua`
2. Translate all strings in the new file
3. Update `Config.Language` to your new language code

### Custom Board Styles

Board styles can be customized in the config:

```lua
Config.BoardStyles = {
    custom_style = {
        model = "your_prop_model",
        scale = 1.0
    }
}
```

### Adding New Templates

1. Place your template image in `html/assets/images/`
2. Update the template selector in `html/index.html`
3. Add corresponding CSS styling if needed

### NUI Focus Management

The system includes comprehensive NUI focus management:

* **Automatic focus restoration** when switching between modals
* **Periodic focus checks** to prevent cursor loss
* **Event-driven focus maintenance** during user interactions
* **Fallback mechanisms** for robust focus handling

## 📝 License

This project is licensed under the MIT License - see the LICENSE file for details.

## 🤝 Support

* **Issues**: [GitHub Issues](https://github.com/arsalan3697/crowe_pinboard/issues)
* **Feature Requests**: [GitHub Discussions](https://github.com/arsalan3697/crowe_pinboard/discussions)
* **Documentation**: See the `config.demo.lua` for detailed configuration examples

## 👥 Contributing

Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.

## 🔄 Recent Updates

### Enhanced Poster Creator

* **Custom Template Import**: Upload any image as a template with validation
* **Advanced Text Editor**: Rich text formatting with precise positioning
* **Real-time Preview**: See changes instantly as you edit
* **System Fonts**: Choose from standard system fonts (Arial, Times New Roman, Georgia, etc.)
* **Enhanced Styling**: Bold, italic, underline, strikethrough with toggle buttons
* **Color Management**: Full color picker with focus preservation

### Improved User Experience

* **Enhanced NUI Focus**: Cursor stays visible throughout all interactions
* **Automatic Post Updates**: Posts appear immediately after creation with smart refresh
* **Better Error Handling**: Comprehensive validation and user feedback
* **Responsive Design**: Improved UI responsiveness and accessibility
* **Modal Management**: Smooth transitions between different UI states

### Technical Improvements

* **Robust Event Handling**: Better communication between client and server
* **Performance Optimization**: Efficient post rendering and updates
* **Memory Management**: Proper cleanup of intervals and event listeners
* **Debug Logging**: Comprehensive debugging for troubleshooting
* **Focus Conflict Prevention**: Smart handling of NUI focus states
* **Control Loop Optimization**: Removed unnecessary timeouts for better performance

### New Features in v1.1.0

* **Posting Fee System**: Configurable fees with job-based reductions and free posting
* **Image Preview System**: Real-time preview of images before posting
* **Expiration Timer Control**: Option to hide countdown timers on specific boards
* **Job-Based Permissions**: Separate job and group permissions for enhanced access control
* **Improved Poster Layout**: Fixed text box positioning to prevent upward shifting

***

**Made with ❤️ for the RedM community**

## 🚀 Enhanced Features

### Real-time Post Updates

* **Immediate Visibility**: Posts appear instantly after creation
* **Automatic Refresh**: Built-in refresh system ensures all posts are synchronized
* **Smart Caching**: Prevents duplicate posts and maintains consistency

### Advanced NUI Focus Management

* **Cursor Persistence**: Cursor remains visible throughout all interactions
* **Modal Transitions**: Smooth focus handling between different UI states
* **Focus Recovery**: Automatic restoration of NUI focus after system events
* **Performance Optimized**: Efficient focus management without delays

### Robust Error Handling

* **Input Validation**: Comprehensive validation for image URLs and poster data
* **User Feedback**: Clear notifications for all actions and errors
* **Fallback Systems**: Multiple refresh mechanisms ensure posts appear
* **Debug Logging**: Comprehensive logging for troubleshooting

### Camera and Interaction

* **Smooth Transitions**: Camera smoothly zooms to pinboard locations
* **Entity Spawning**: Dynamic bounty board spawning within radius
* **Interaction Prompts**: Clear visual prompts for user interaction
* **Distance Management**: Smart spawning and despawning of board entities


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://crowescripts.gitbook.io/documentation/about-our-scripts/redm-script-documentation/crowe-pinboard.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
