# Frontend Implementation Guide - Calendar & Meetings

## Quick Start Checklist

### 1. Install Calendar Library
```bash
npm install @fullcalendar/core @fullcalendar/vue3 @fullcalendar/daygrid @fullcalendar/timegrid @fullcalendar/interaction
```

### 2. Create Required Pages

Create these files in `resources/js/pages/Meetings/`:

#### A. MeetingsIndex.vue
**Purpose**: List all meetings with filters
**Features**:
- DataTable with meetings
- Search by title/description
- Filter by status, client, date range
- Actions: View, Edit, Delete, Update Status

**Key Props from Backend**:
```javascript
{
  meetings: { data: [], meta: {} },  // Paginated
  filters: { search, status, client_id, start_date, end_date },
  clients: [],
  statuses: []
}
```

#### B. MeetingsForm.vue
**Purpose**: Create/Edit meeting
**Features**:
- Form fields: title, description, client (optional), start_time, end_time, location, meeting_link, attendees
- Date/time pickers
- Multi-select for attendees
- Validation

**Key Props from Backend**:
```javascript
{
  meeting: {},  // When editing
  clients: [],
  users: [],
  statuses: []
}
```

#### C. MeetingDetails.vue
**Purpose**: View meeting details
**Features**:
- Display all meeting information
- Show attendees with avatars and responses
- Show associated client
- Actions: Edit, Delete, Update Status, Join Meeting (if link exists)

**Key Props from Backend**:
```javascript
{
  meeting: {
    id, title, description, client, start_time, end_time,
    location, meeting_link, status, attendees, creator, duration_minutes
  }
}
```

#### D. MyCalendar.vue
**Purpose**: Personal calendar view
**Features**:
- Calendar showing meetings and task deadlines
- Month/Week/Day views
- Click event to view details
- Color coding: meetings (blue), tasks (green/yellow/red by priority)

**Key Props from Backend**:
```javascript
{
  meetings: [],  // User's meetings
  tasks: [],     // User's tasks with deadlines
  filters: { start_date, end_date }
}
```

**Calendar Events Format**:
```javascript
const events = [
  // Meetings
  ...meetings.map(meeting => ({
    id: `meeting-${meeting.id}`,
    title: meeting.title,
    start: meeting.start_time,
    end: meeting.end_time,
    backgroundColor: '#3b82f6',  // Blue for meetings
    extendedProps: {
      type: 'meeting',
      data: meeting
    }
  })),
  // Tasks
  ...tasks.map(task => ({
    id: `task-${task.id}`,
    title: task.title,
    start: task.deadline,
    allDay: true,
    backgroundColor: getPriorityColor(task.priority),
    extendedProps: {
      type: 'task',
      data: task
    }
  }))
];
```

#### E. ScheduleMeeting.vue
**Purpose**: Schedule meeting with team availability
**Features**:
- Multi-select for team members
- Combined calendar showing all selected users' meetings and tasks
- Visual conflict detection
- Create meeting button

**Key Props from Backend**:
```javascript
{
  selectedUsers: [],
  allUsers: [],
  meetings: [],  // All meetings for selected users
  tasks: [],     // All tasks for selected users
  clients: [],
  filters: { user_ids, start_date, end_date }
}
```

### 3. Add Routes to Frontend Router

If using Vue Router, add these routes:

```javascript
{
  path: '/calendar/my',
  name: 'calendar.my',
  component: () => import('@/pages/Meetings/MyCalendar.vue'),
  meta: { requiresAuth: true, permission: 'meetings.view' }
},
{
  path: '/meetings',
  name: 'meetings.index',
  component: () => import('@/pages/Meetings/MeetingsIndex.vue'),
  meta: { requiresAuth: true, permission: 'meetings.view' }
},
{
  path: '/meetings/create',
  name: 'meetings.create',
  component: () => import('@/pages/Meetings/MeetingsForm.vue'),
  meta: { requiresAuth: true, permission: 'meetings.create' }
},
{
  path: '/meetings/:id',
  name: 'meetings.show',
  component: () => import('@/pages/Meetings/MeetingDetails.vue'),
  meta: { requiresAuth: true, permission: 'meetings.view' }
},
{
  path: '/meetings/:id/edit',
  name: 'meetings.edit',
  component: () => import('@/pages/Meetings/MeetingsForm.vue'),
  meta: { requiresAuth: true, permission: 'meetings.edit' }
},
{
  path: '/meetings/schedule',
  name: 'meetings.schedule',
  component: () => import('@/pages/Meetings/ScheduleMeeting.vue'),
  meta: { requiresAuth: true, permission: 'meetings.create' }
}
```

### 4. Update Sidebar Component

Add these menu items to your sidebar:

```vue
<template>
  <!-- After Tasks section -->
  <SidebarItem
    :to="{ name: 'calendar.my' }"
    icon="CalendarIcon"
    :label="$t('sidebar.myCalendar')"
  />
  
  <SidebarItem
    :to="{ name: 'meetings.index' }"
    icon="UsersIcon"
    :label="$t('sidebar.meetings')"
  />
  
  <SidebarItem
    :to="{ name: 'meetings.schedule' }"
    icon="CalendarPlusIcon"
    :label="$t('sidebar.scheduleMeeting')"
  />
</template>
```

### 5. Sample FullCalendar Implementation

```vue
<template>
  <div class="calendar-container">
    <FullCalendar :options="calendarOptions" />
  </div>
</template>

<script setup>
import { ref, computed } from 'vue';
import FullCalendar from '@fullcalendar/vue3';
import dayGridPlugin from '@fullcalendar/daygrid';
import timeGridPlugin from '@fullcalendar/timegrid';
import interactionPlugin from '@fullcalendar/interaction';

const props = defineProps({
  meetings: Array,
  tasks: Array
});

const calendarOptions = computed(() => ({
  plugins: [dayGridPlugin, timeGridPlugin, interactionPlugin],
  initialView: 'dayGridMonth',
  headerToolbar: {
    left: 'prev,next today',
    center: 'title',
    right: 'dayGridMonth,timeGridWeek,timeGridDay'
  },
  events: [
    ...props.meetings.map(meeting => ({
      id: `meeting-${meeting.id}`,
      title: meeting.title,
      start: meeting.start_time,
      end: meeting.end_time,
      backgroundColor: '#3b82f6',
      borderColor: '#2563eb',
      extendedProps: {
        type: 'meeting',
        data: meeting
      }
    })),
    ...props.tasks.map(task => ({
      id: `task-${task.id}`,
      title: task.title,
      start: task.deadline,
      allDay: true,
      backgroundColor: getPriorityColor(task.priority),
      extendedProps: {
        type: 'task',
        data: task
      }
    }))
  ],
  eventClick: handleEventClick,
  dateClick: handleDateClick,
  editable: false,
  selectable: true
}));

const getPriorityColor = (priority) => {
  const colors = {
    low: '#10b981',
    medium: '#f59e0b',
    high: '#ef4444'
  };
  return colors[priority] || '#6b7280';
};

const handleEventClick = (info) => {
  const { type, data } = info.event.extendedProps;
  if (type === 'meeting') {
    router.push({ name: 'meetings.show', params: { id: data.id } });
  } else if (type === 'task') {
    router.push({ name: 'tasks.show', params: { id: data.id } });
  }
};

const handleDateClick = (info) => {
  // Optionally navigate to create meeting with pre-filled date
  router.push({
    name: 'meetings.create',
    query: { date: info.dateStr }
  });
};
</script>

<style scoped>
.calendar-container {
  background: white;
  border-radius: 0.5rem;
  padding: 1.5rem;
  box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
}
</style>
```

### 6. API Calls Examples

```javascript
// Get meetings
const getMeetings = async (filters = {}) => {
  const response = await axios.get('/meetings', { params: filters });
  return response.data;
};

// Create meeting
const createMeeting = async (data) => {
  const response = await axios.post('/meetings', data);
  return response.data;
};

// Update meeting
const updateMeeting = async (id, data) => {
  const response = await axios.put(`/meetings/${id}`, data);
  return response.data;
};

// Delete meeting
const deleteMeeting = async (id) => {
  await axios.delete(`/meetings/${id}`);
};

// Update meeting status
const updateMeetingStatus = async (id, status) => {
  const response = await axios.post(`/meetings/${id}/update-status`, { status });
  return response.data;
};

// Get user availability
const getUserAvailability = async (userIds, startDate, endDate) => {
  const response = await axios.post('/meetings/availability', {
    user_ids: userIds,
    start_date: startDate,
    end_date: endDate
  });
  return response.data;
};

// Get my calendar
const getMyCalendar = async (startDate, endDate) => {
  const response = await axios.get('/calendar/my', {
    params: { start_date: startDate, end_date: endDate }
  });
  return response.data;
};
```

### 7. Form Validation Example

```javascript
const validateMeetingForm = (form) => {
  const errors = {};
  
  if (!form.title) {
    errors.title = t('meetings.validation.titleRequired');
  }
  
  if (!form.start_time) {
    errors.start_time = t('meetings.validation.startTimeRequired');
  }
  
  if (!form.end_time) {
    errors.end_time = t('meetings.validation.endTimeRequired');
  }
  
  if (form.start_time && form.end_time) {
    if (new Date(form.end_time) <= new Date(form.start_time)) {
      errors.end_time = t('meetings.validation.endTimeAfterStart');
    }
  }
  
  if (!form.attendee_ids || form.attendee_ids.length === 0) {
    errors.attendee_ids = t('meetings.validation.attendeesRequired');
  }
  
  if (form.start_time && new Date(form.start_time) < new Date()) {
    errors.start_time = t('meetings.validation.startTimeInFuture');
  }
  
  return errors;
};
```

### 8. Status Badge Component Example

```vue
<template>
  <span
    class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium"
    :class="statusClass"
  >
    {{ statusLabel }}
  </span>
</template>

<script setup>
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';

const props = defineProps({
  status: {
    type: String,
    required: true
  }
});

const { t } = useI18n();

const statusLabel = computed(() => t(`meetings.status.${props.status}`));

const statusClass = computed(() => {
  const classes = {
    scheduled: 'bg-blue-100 text-blue-800',
    in_progress: 'bg-yellow-100 text-yellow-800',
    completed: 'bg-green-100 text-green-800',
    cancelled: 'bg-red-100 text-red-800'
  };
  return classes[props.status] || 'bg-gray-100 text-gray-800';
});
</script>
```

### 9. Date/Time Formatting

```javascript
import { format, formatDistance } from 'date-fns';
import { ar, enUS } from 'date-fns/locale';

// Format date/time
const formatDateTime = (dateTime, locale = 'en') => {
  const locales = { ar, en: enUS };
  return format(new Date(dateTime), 'PPp', { locale: locales[locale] });
};

// Format relative time
const formatRelative = (dateTime, locale = 'en') => {
  const locales = { ar, en: enUS };
  return formatDistance(new Date(dateTime), new Date(), {
    addSuffix: true,
    locale: locales[locale]
  });
};

// Format duration
const formatDuration = (minutes) => {
  const hours = Math.floor(minutes / 60);
  const mins = minutes % 60;
  
  if (hours > 0) {
    return `${hours}h ${mins}m`;
  }
  return `${mins}m`;
};
```

### 10. Conflict Detection Example

```javascript
const checkConflicts = (newMeeting, existingMeetings) => {
  const newStart = new Date(newMeeting.start_time);
  const newEnd = new Date(newMeeting.end_time);
  
  return existingMeetings.filter(meeting => {
    if (meeting.status === 'cancelled') return false;
    
    const existingStart = new Date(meeting.start_time);
    const existingEnd = new Date(meeting.end_time);
    
    // Check if times overlap
    return (newStart < existingEnd && newEnd > existingStart);
  });
};

const hasConflicts = computed(() => {
  return checkConflicts(form, meetings).length > 0;
});
```

## Testing Checklist

- [ ] Create a meeting
- [ ] Edit a meeting
- [ ] Delete a meeting
- [ ] View meeting details
- [ ] Update meeting status
- [ ] View personal calendar
- [ ] Filter meetings by status
- [ ] Filter meetings by client
- [ ] Search meetings
- [ ] Schedule meeting with team availability
- [ ] Check conflict detection
- [ ] Test with different user roles (admin, manager, employee)
- [ ] Test RTL layout (Arabic)
- [ ] Test responsive design (mobile, tablet, desktop)

## Common Issues & Solutions

### Issue: Calendar not displaying events
**Solution**: Ensure date formats are ISO 8601 strings (YYYY-MM-DDTHH:mm:ss)

### Issue: Permissions not working
**Solution**: Clear cache and re-seed roles: `php artisan cache:clear && php artisan db:seed --class=RolesSeeder`

### Issue: Translations not showing
**Solution**: Check that translation keys match exactly, including case

### Issue: Date picker showing wrong timezone
**Solution**: Ensure backend returns dates in user's timezone or UTC with proper conversion

## Next Steps

1. Install FullCalendar
2. Create the 5 Vue pages
3. Add sidebar menu items
4. Test basic CRUD operations
5. Implement conflict detection
6. Add notifications
7. Test with different roles
8. Add English translations
