# Plugins & Utilities Reference

Complete reference for all AwesCode UI plugins and utility methods available in your application.

## Overview

AwesCode UI provides several plugins that extend Nuxt with custom functionality:

| Plugin | Purpose | Available As |
|--------|---------|--------------|
| **core** | Notifications, config access | `$notify`, `$confirm`, `$awes` |
| **screen** | Responsive breakpoints | `$screen` |
| **dayjs** | Date formatting | `$dayjs` |
| **router** | Router extensions | `router.pushBack`, `router.setBack` |
| **dark-theme** | Theme management | `$store.commit('awesIo/SET_DARK_THEME')`, `$store.getters['awesIo/isDarkTheme']` |
| **permissions** | CASL permissions | `$can`, `$cannot` |

All plugins are automatically registered by the `@awes-io/ui` Nuxt module.

## $notify

Display toast notifications to users.

### Basic Usage

```javascript
// Success notification
this.$notify({
    title: 'Customer saved successfully',
    type: 'success'
})

// Error notification
this.$notify({
    title: 'Failed to load data',
    type: 'error'
})

// Warning notification
this.$notify({
    title: 'Data may be outdated',
    type: 'warning'
})

// Info notification
this.$notify({
    title: 'Processing request...',
    type: 'info'
})
```

### Notification Types

```javascript
// Success (green)
this.$notify({
    title: 'Operation completed',
    type: 'success'
})

// Error (red)
this.$notify({
    title: 'Something went wrong',
    type: 'error'
})

// Warning (yellow/orange)
this.$notify({
    title: 'Please review your input',
    type: 'warning'
})

// Info (blue)
this.$notify({
    title: 'Your session will expire in 5 minutes',
    type: 'info'
})
```

### With Duration

```javascript
// Auto-dismiss after 5 seconds (default)
this.$notify({
    title: 'Auto-dismiss notification'
})

// Auto-dismiss after 10 seconds
this.$notify({
    title: 'Longer notification',
    timeout: 10000
})

// Never auto-dismiss (requires manual close)
this.$notify({
    title: 'Important: Please read carefully',
    timeout: 0
})
```

### With Title

```javascript
this.$notify({
    title: 'Success',
    text: 'Customer profile updated successfully',
    type: 'success'
})

this.$notify({
    title: 'Error',
    text: 'Unable to connect to server',
    type: 'error'
})
```

### Common Patterns

```javascript
// After successful save
async save() {
    try {
        await this.customer.save()

        this.$notify({
            title: 'Customer saved successfully',
            type: 'success'
        })

        this.$router.push('/customers')
    } catch (error) {
        this.$notify({
            title: 'Failed to save customer',
            type: 'error'
        })
    }
}

// After successful delete
async delete() {
    await this.$axios.delete(`/api/customers/${id}`)

    this.$notify({
        title: 'Customer deleted',
        type: 'success'
    })
}

// Network error
catch (error) {
    if (!error.response) {
        this.$notify({
            title: 'Network error. Please check your connection.',
            type: 'error'
        })
    }
}

// Bulk action
this.$notify({
    title: `${count} customers updated`,
    type: 'success'
})
```

## $confirm

Show confirmation dialogs for destructive actions.

### Basic Usage

```javascript
const confirmed = await this.$confirm({
    title: 'Delete Customer',
    message: 'Are you sure you want to delete this customer?'
})

if (confirmed) {
    // User clicked "Confirm"
    await this.deleteCustomer()
} else {
    // User clicked "Cancel" or closed dialog
}
```

### With Custom Button Text

```javascript
const confirmed = await this.$confirm({
    title: 'Permanent Delete',
    message: 'This will permanently delete all data. This action cannot be undone.',
    confirmText: 'Yes, Delete Everything',
    cancelText: 'No, Keep It'
})
```

### Delete Pattern

```javascript
async deleteCustomer(customer) {
    const confirmed = await this.$confirm({
        title: 'Delete Customer',
        message: `Are you sure you want to delete ${customer.name}?`
    })

    if (!confirmed) {
        return
    }

    try {
        await this.$axios.delete(`/api/customers/${customer.id}`)

        this.$notify({
            title: 'Customer deleted',
            type: 'success'
        })

        await this.customers.fetch()
    } catch (error) {
        this.$notify({
            title: 'Failed to delete customer',
            type: 'error'
        })
    }
}
```

### Discard Changes Pattern

```javascript
async leave() {
    if (this.hasUnsavedChanges) {
        const confirmed = await this.$confirm({
            title: 'Unsaved Changes',
            message: 'You have unsaved changes. Are you sure you want to leave?',
            confirmText: 'Leave',
            cancelText: 'Stay'
        })

        if (!confirmed) {
            return
        }
    }

    this.$router.push('/customers')
}
```

### With Navigation Guard

```javascript
export default {
    beforeRouteLeave(to, from, next) {
        if (this.hasUnsavedChanges) {
            this.$confirm({
                title: 'Unsaved Changes',
                message: 'Are you sure you want to leave?'
            }).then(confirmed => {
                if (confirmed) {
                    next()
                } else {
                    next(false)
                }
            })
        } else {
            next()
        }
    }
}
```

## $screen

Reactive responsive breakpoints.

### Breakpoint Values

```javascript
// Breakpoints (following Tailwind defaults)
$screen.sm   // >= 640px
$screen.md   // >= 768px
$screen.lg   // >= 1024px
$screen.xl   // >= 1280px
$screen.xxl  // >= 1536px
```

### Usage in Templates

```markup
<template>
    <div>
        <!-- Mobile only -->
        <div v-if="!$screen.md">
            Mobile menu
        </div>

        <!-- Desktop only -->
        <div v-if="$screen.md">
            Desktop menu
        </div>

        <!-- Responsive columns -->
        <AwGrid :col="$screen.md ? 2 : 1">
            <div>Column 1</div>
            <div>Column 2</div>
        </AwGrid>

        <!-- Conditional component -->
        <AwTable v-if="$screen.lg" :collection="items" />
        <AwCard v-else v-for="item in items" :key="item.id">
            {{ item.name }}
        </AwCard>
    </div>
</template>
```

### Usage in Methods

```javascript
export default {
    methods: {
        openSidebar() {
            // On mobile, open as modal
            if (!this.$screen.md) {
                this.showMobileMenu = true
            }
        },

        getTableColumns() {
            // Fewer columns on mobile
            if (this.$screen.sm) {
                return ['name', 'email', 'phone', 'created_at']
            }
            return ['name', 'email']
        }
    }
}
```

### Usage in Computed

```javascript
export default {
    computed: {
        isMobile() {
            return !this.$screen.md
        },

        columns() {
            if (this.$screen.xl) {
                return 4
            }
            if (this.$screen.lg) {
                return 3
            }
            if (this.$screen.md) {
                return 2
            }
            return 1
        }
    }
}
```

### Reactive Updates

`$screen` is reactive - components automatically update when breakpoints change:

```markup
<template>
    <div>
        <!-- Automatically updates on resize -->
        <p>Current breakpoint: {{ currentBreakpoint }}</p>
    </div>
</template>

<script>
export default {
    computed: {
        currentBreakpoint() {
            if (this.$screen.xxl) return 'xxl'
            if (this.$screen.xl) return 'xl'
            if (this.$screen.lg) return 'lg'
            if (this.$screen.md) return 'md'
            if (this.$screen.sm) return 'sm'
            return 'xs'
        }
    }
}
</script>
```

## $dayjs

Date formatting and manipulation using Day.js library.

**⚠️ CRITICAL: Always use `$dayjs`, never use native `Date` constructor**

The framework uses Day.js for all date operations. Using native JavaScript `Date` constructor can cause timezone issues, inconsistent formatting, and compatibility problems. Always use `$dayjs` (in templates) or `this.$dayjs` (in methods) instead of `new Date()`.

```javascript
// ❌ BAD - Never use native Date
const date = new Date(value)
date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })

// ✅ GOOD - Always use $dayjs
this.$dayjs(value).format('MMM D, YYYY')
```

### IMPORTANT: Template vs Method Usage

```markup
<template>
    <!-- ✅ GOOD: In templates, use $dayjs WITHOUT this -->
    {{ $dayjs(date).format('ll') }}
</template>

<script>
export default {
    methods: {
        formatDate(date) {
            // ✅ GOOD: In methods, use this.$dayjs WITH this
            return this.$dayjs(date).format('ll')
        }
    }
}
</script>
```

### Common Date Formats

```javascript
const date = '2024-01-15'

// Short date: Jan 15, 2024
this.$dayjs(date).format('ll')

// Long date: January 15, 2024
this.$dayjs(date).format('LL')

// Short date + time: Jan 15, 2024 2:30 PM
this.$dayjs(date).format('lll')

// Long date + time: January 15, 2024 2:30 PM
this.$dayjs(date).format('LLL')

// Full: Monday, January 15, 2024 2:30 PM
this.$dayjs(date).format('LLLL')

// Month and year: January 2024
this.$dayjs(date).format('MMMM YYYY')

// ISO format: 2024-01-15T14:30:00Z
this.$dayjs(date).toISOString()

// Relative time: 2 hours ago
this.$dayjs(date).fromNow()
```

### Template Usage

```markup
<template>
    <div>
        <!-- Short date -->
        <p>{{ $dayjs(customer.created_at).format('ll') }}</p>

        <!-- Month and year -->
        <p>{{ $dayjs(order.date).format('MMMM YYYY') }}</p>

        <!-- Relative time -->
        <p>Updated {{ $dayjs(item.updated_at).fromNow() }}</p>

        <!-- Custom format -->
        <p>{{ $dayjs(event.date).format('MMM D, YYYY [at] h:mm A') }}</p>
    </div>
</template>
```

### Common Patterns

```javascript
// Display created date
computed: {
    createdDate() {
        return this.$dayjs(this.customer.created_at).format('ll')
    }
}

// Display relative time
computed: {
    lastUpdated() {
        return this.$dayjs(this.item.updated_at).fromNow()
    }
}

// Filter by date range
methods: {
    filterByMonth(month, year) {
        const start = this.$dayjs(`${year}-${month}-01`).startOf('month')
        const end = this.$dayjs(`${year}-${month}-01`).endOf('month')

        return this.items.filter(item => {
            const date = this.$dayjs(item.date)
            return date.isAfter(start) && date.isBefore(end)
        })
    }
}

// Sort by date
methods: {
    sortByDate() {
        return this.items.sort((a, b) => {
            return this.$dayjs(a.date).diff(this.$dayjs(b.date))
        })
    }
}
```

### Date Manipulation

```javascript
// Add time
this.$dayjs().add(7, 'day')       // 7 days from now
this.$dayjs().add(1, 'month')     // 1 month from now
this.$dayjs().add(2, 'year')      // 2 years from now

// Subtract time
this.$dayjs().subtract(3, 'day')  // 3 days ago
this.$dayjs().subtract(1, 'week') // 1 week ago

// Start/end of period
this.$dayjs().startOf('month')    // First day of month
this.$dayjs().endOf('month')      // Last day of month
this.$dayjs().startOf('week')     // Start of week (Sunday)

// Comparison
const date1 = this.$dayjs('2024-01-15')
const date2 = this.$dayjs('2024-02-20')

date1.isBefore(date2)  // true
date1.isAfter(date2)   // false
date1.isSame(date2)    // false

// Difference
date2.diff(date1, 'day')    // 36 days
date2.diff(date1, 'month')  // 1 month
```

## router.pushBack / router.setBack

Navigate back to a specific route.

### Basic Usage

```javascript
// Set where "back" should go
this.$router.setBack('/customers')

// Navigate back
this.$router.pushBack()
```

### Common Pattern

```javascript
// On list page - set back route
mounted() {
    this.$router.setBack('/customers')
}

// On detail page - go back
methods: {
    cancel() {
        this.$router.pushBack()
    }
}
```

### With Fallback

```javascript
// Go back, or fallback to /dashboard
this.$router.pushBack('/dashboard')
```

### Complete Example

```markup
<!-- List Page -->
<script>
export default {
    mounted() {
        // Set back route for detail pages
        this.$router.setBack(`/shops/${this.$route.params.shop_uuid}/customers`)
    },

    methods: {
        viewCustomer(customer) {
            this.$router.push(`/shops/${this.$route.params.shop_uuid}/customers/${customer.id}`)
        }
    }
}
</script>

<!-- Detail Page -->
<script>
export default {
    methods: {
        async save() {
            await this.customer.save()

            this.$notify({
                title: 'Customer saved',
                type: 'success'
            })

            // Go back to list
            this.$router.pushBack(`/shops/${this.$route.params.shop_uuid}/customers`)
        },

        cancel() {
            // Go back without saving
            this.$router.pushBack(`/shops/${this.$route.params.shop_uuid}/customers`)
        }
    }
}
</script>
```

## $awes

Access AwesCode UI configuration and utilities.

### Configuration Access

```javascript
// Get component config
const buttonConfig = this.$awes.config.AwButton

// Get global config
const apiUrl = this.$awes.config.apiUrl
```

### Usage

```javascript
export default {
    computed: {
        defaultButtonSize() {
            return this.$awes.config.AwButton?.size || 'md'
        }
    }
}
```

## $can / $cannot (CASL Permissions)

Check user permissions (if CASL is configured).

### Basic Usage

```markup
<template>
    <div>
        <!-- Show button only if user can create -->
        <AwButton v-if="$can('create', 'Customer')">
            Add Customer
        </AwButton>

        <!-- Show button only if user can edit -->
        <AwButton v-if="$can('update', customer)">
            Edit
        </AwButton>

        <!-- Show button only if user can delete -->
        <AwButton v-if="$can('delete', customer)">
            Delete
        </AwButton>

        <!-- Inverse check -->
        <p v-if="$cannot('view', 'Reports')">
            You don't have access to reports
        </p>
    </div>
</template>
```

### In Methods

```javascript
export default {
    methods: {
        async deleteCustomer(customer) {
            // Check permission
            if (!this.$can('delete', customer)) {
                this.$notify({
                    title: 'You do not have permission to delete this customer',
                    type: 'error'
                })
                return
            }

            // Proceed with delete
            await this.$axios.delete(`/api/customers/${customer.id}`)
        }
    }
}
```

## Dark Theme Management

Toggle between light and dark themes using Vuex store.

### Basic Usage

```markup
<template>
    <AwButton @click="toggleTheme">
        Toggle Theme
    </AwButton>
</template>

<script>
export default {
    methods: {
        toggleTheme() {
            const currentTheme = this.$store.getters['awesIo/isDarkTheme']
            this.$store.commit('awesIo/SET_DARK_THEME', !currentTheme)
        }
    }
}
</script>
```

### Using v-model with Switcher

```markup
<template>
    <AwSwitcher v-model="isDarkTheme" size="lg" />
</template>

<script>
export default {
    computed: {
        isDarkTheme: {
            get() {
                return this.$store.getters['awesIo/isDarkTheme']
            },
            set(val) {
                this.$store.commit('awesIo/SET_DARK_THEME', val)
            }
        }
    }
}
</script>
```

### With Icon Button

```markup
<template>
    <AwButton @click="toggleTheme">
        <AwIcon :name="isDarkTheme ? 'sun' : 'moon'" />
        {{ isDarkTheme ? 'Light Mode' : 'Dark Mode' }}
    </AwButton>
</template>

<script>
export default {
    computed: {
        isDarkTheme() {
            return this.$store.getters['awesIo/isDarkTheme']
        }
    },

    methods: {
        toggleTheme() {
            this.$store.commit('awesIo/SET_DARK_THEME', !this.isDarkTheme)
        }
    }
}
</script>
```

## Complete Examples

### Form with Full Error Handling

```markup
<template>
    <AwPageSingle
        hide-menu
        :title="customer.isNew() ? 'New Customer' : 'Edit Customer'"
    >
        <AwCard title="Customer Information">
            <AwInput
                v-model="customer.name"
                :error="customer.errors.name"
                label="Name"
            />

            <AwInput
                v-model="customer.email"
                :error="customer.errors.email"
                label="Email"
                type="email"
            />

            <AwDate
                v-model="customer.birthday"
                :error="customer.errors.birthday"
                label="Birthday"
            />

            <!-- Display formatted date -->
            <p v-if="customer.birthday">
                Birthday: {{ $dayjs(customer.birthday).format('LL') }}
            </p>
        </AwCard>

        <template #buttons>
            <AwButton
                :loading="saving"
                color="accent"
                @click="save"
            >
                Save
            </AwButton>

            <AwButton @click="cancel">
                Cancel
            </AwButton>
        </template>
    </AwPageSingle>
</template>

<script>
import Customer from '~/models/Customer'

export default {
    data() {
        return {
            customer: new Customer(
                {},
                null,
                { shop_uuid: this.$route.params.shop_uuid }
            ),
            saving: false
        }
    },

    methods: {
        async save() {
            this.saving = true

            try {
                await this.customer.save()

                if (Object.keys(this.customer.errors).length > 0) {
                    this.$notify({
                        title: 'Please fix validation errors',
                        type: 'error'
                    })
                    return
                }

                this.$notify({
                    title: 'Customer saved successfully',
                    type: 'success'
                })

                this.$router.pushBack(`/shops/${this.$route.params.shop_uuid}/customers`)
            } catch (error) {
                this.$notify({
                    title: 'Failed to save customer',
                    type: 'error'
                })
            } finally {
                this.saving = false
            }
        },

        cancel() {
            this.$router.pushBack(`/shops/${this.$route.params.shop_uuid}/customers`)
        }
    }
}
</script>
```

### Responsive Table

```markup
<template>
    <AwPage title="Customers">
        <template #buttons>
            <AwButton
                v-if="$can('create', 'Customer')"
                :href="`/shops/${$route.params.shop_uuid}/customers/new`"
                color="accent"
            >
                Add Customer
            </AwButton>
        </template>

        <!-- Desktop table -->
        <AwTableBuilder
            v-if="$screen.md"
            :collection="customers"
            @click:row="viewCustomer"
        >
            <AwTableCol field="name" title="Name" />
            <AwTableCol field="email" title="Email" />
            <AwTableCol field="phone" title="Phone" />
            <AwTableCol field="created_at" title="Created">
                <template #default="{ cell }">
                    {{ $dayjs(cell).format('ll') }}
                </template>
            </AwTableCol>
        </AwTableBuilder>

        <!-- Mobile cards -->
        <div v-else>
            <AwCard
                v-for="customer in customers.models"
                :key="customer.id"
                class="mb-4"
                @click="viewCustomer(customer)"
            >
                <h3>{{ customer.name }}</h3>
                <p>{{ customer.email }}</p>
                <p class="text-sm text-gray-500">
                    Created {{ $dayjs(customer.created_at).fromNow() }}
                </p>
            </AwCard>
        </div>
    </AwPage>
</template>

<script>
import Customers from '~/collections/Customers'

export default {
    data() {
        return {
            customers: new Customers([], {
                shop_uuid: this.$route.params.shop_uuid
            })
        }
    },

    mounted() {
        this.$router.setBack(`/shops/${this.$route.params.shop_uuid}/customers`)
    },

    methods: {
        viewCustomer(customer) {
            this.$router.push(`/shops/${this.$route.params.shop_uuid}/customers/${customer.id}`)
        }
    }
}
</script>
```

## See Also

- [Error Handling Guide](../guides/error-handling.md) - Using $notify and $confirm
- [Data Fetching Guide](../guides/data-fetching.md) - Using date formatting in templates
- [Best Practices Guide](../guides/best-practices.md) - Plugin usage patterns
