Advertisement
  1. Code
  2. PHP

Створення стартапу: налаштування режиму перегляду

Scroll to top
Read Time: 18 min

Ukrainian (українська мова) translation by Elen (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

Введення

Дана стаття є частиною серії Building Your Startup With PHP series на Envato Tuts+. В цій статті я проведу вас через процес запуску стартапа від концепції до результату за допомогою програми Meeting Planner, як реального прикладу. На кожному кроці нашого шляху я даватиму вам код Meeting Planner, як відкритий ресурс, на прикладі якого ви можете вчитися. Я також вирішуватиму ділові питання, які мають відношення до стартапу, по ходу їх виникнення.

Чому в цій серії є прогалина?

Ви, мабуть, помітили, що між попереднім випуском і даною статтею величезний проміжок часу. В квітні 2015 року мені поставили діагноз "пухлина головного мозку", що вимагало хірургічного втручання і хіміотерапію. Мені неймовірно пощастило - про мене дуже добре піклувалися і все йшло добре, мало у кого є доступ до хорошої нейрохірургії, який отримав я на північно-західному тихоокеанському побережжі. З того часу я продовжував писати для Envato Tuts+, проте це так чудово повернутися до серії стартапів і зосередитись на ній. Сподіваюсь вона вам також сподобається.

Що ми розглянемо в даній статті?

У цьому уроці ми розглянемо користувацькі функції, які необхідні для забезпечення різних режимів перегляду залежно від того, хто переглядає запрошення на зустріч чи збори. Перш ніж ми почнемо розсилати учасникам запрошення по email, ми повинні мати готовий режим перегляду з чітко визначеним функціоналом, яким ми можемо поділитися. По суті, ми прагнемо переконатися, що режим перегляду якнайкраще задовольняє організатора зустрічі і її учасників. Слідуйте далі, щоб дізнатись, що вам необхідно.

Весь код для Meeting Planner написаний в Yii2 Framework для PHP, який має вбудовану підтримку для I18n. Якщо ви хотіли б дізнатися більше про Yii2, ознайомтеся з нашою схожою серією Programming With Yii2 на Envato Tuts+.

Цікаво, що нещодавно інвестор зацікавився в тому, щоб надати ресурси для прискорення розвитку процесу на нашому сайті, а значить він бачить значимість цієї концепції. Як тільки я знайду найкращий шлях, щоб просуватися далі, я дам вам знати. В будь-якому випадку, я сподіваюся, що це створює певну інтригу щодо тем нових навчальних статей по управлінню інвестиційними процесами для підприємців.

Про всяк випадок нагадаю: я беру участь в обговоренні питань в коментарях. Мені особливо цікаво, якщо у вас є різні підходи, додаткові ідеї або ви хочете запропонувати нову тему для майбутніх статей. Ви також можете зв'язатися зі мною на Twitter @reifman.

Вимоги до режиму перегляду, Meeting View

В цьому є щось захоплююче - скоро Meeting Planner надаватиме запрошення своїм учасникам. Проте, щоб підтримати це, ми повинні бути певні, що інтерфейс сторінки вірно налаштований. Якщо ви створили зустріч, у вас є певні права, такі як запрошення учасників, пропозиції щодо місць проведення, визначення дати і часу, а також право остаточного вибору. У деяких випадках організатор може запропонувати окремі або всі переваги також і учасникам.

По суті, ми повинні знати, хто переглядає сторінку зустрічі, щоб потім налаштувати її інтерфейс з доступними опціями. Yii виконує більшість з цих завдань досить легко, проте тут зав'язано багато деталей.

Коротке пояснення щодо UХ

Перш за все дозвольте сказати, що для мінімальної життєздатності продукту (MVP), потрібно буде зробити багато роботи в сфері UX, а щось і перероблювати час від часу. Основне, над чим я зараз працюю - це базовий функціонал, щоб отримати альфа-версію для практичного використання. Я знаю, поки що в деяких місцях виглядає досить грубувато і не завжди відповідає інтуїтивному використанню, так, як вам би хотілося. Також є неефективним код, який в майбутньому буде оптимізовано. Будь ласка, залишайте ваші думки і коментарі нижче і я врахую їх в процесі роботи.

Поточний інтерфейс сторінки Meeting View

Ось як виглядає на даний момент сторінка meeting view, яку бачить її автор (або власник):

Customizing Meeting View - The Existing Codes Meeting ViewCustomizing Meeting View - The Existing Codes Meeting ViewCustomizing Meeting View - The Existing Codes Meeting View

Кнопка Send відправляє email з запрошенням на зустріч, а також передбачає для учасників опцію зворотного зв'язку.  Чекбокси You і Them внизу дозволяють тому, хто переглядає, вказати, чи підходить для них локація (-ї) і час (години) роботи. Чекбокси Choose дозволяють користувачу остаточно обрати місце і час. Кнопка Finalize розміщує зустрічі з обраним місцем і параметрами часу у розкладі.

Звичайно, коли продукт буде готовим, нам захочеться багато в чому покращити і "відшліфувати" UX, проте зараз у нас є пригоршня функціональних елементів, які ми б хотіли модифікувати для користувачів:

  • В кнопці Send не буде необхідності після того, як адресат отримає запрошення.
  • Учасники матимуть або не матимуть можливості натиснути Finalize - робити фінальні налаштування зустрічі.
  • Учасники не зможуть редагувати текст щодо деталей зустрічі (Edit (іконка "ручка")).
  • Учасники не зможуть додавати учасників в зазначений час (People (для наших MVP)).
  • Учасники матимуть або не матимуть можливість додавати нові місця (Places (іконка "+")).
  • Учасникам дозволяється або не дозволяється додавати дати і час, Dates & Times (іконка "+").
  • На обох панелях, Places і Dates & Times, ми б хотіли показувати актуальний вибір користувача під колонкою You і інформацію про інших осіб - в Them.
  • На обох панелях Places і Dates & Times, учасники можуть або не можуть обирати, Choose, остаточну локацію і час.

Всі ці функції потрібно обдумати в вашій роботі сьогодні. Давайте поглянемо, що необхідно для побудови цих опцій.

Вимоги до виконання

Якщо ви слідкуєте за кодом, ви можете знайти оновлення, які я тут описую, на GitHub.

Хто переглядає сторінку в даний момент

Yii Framework передбачає поточний user_id глядача тут:

1
$user_id = Yii::$app->user->getId()

Модель Meeting має властивість $owner_id і функцію isOwner, щоб перевірити, чи є переглядач власником, ініціатором зустрічі. Якщо ні, переглядач матиме умовно менше функцій контролю на зустрічі.

Я створив кілька допоміжних функцій в моделі Meeting, для прискорення процесу:

1
public function setViewer() {
2
      $this->viewer_id = Yii::$app->user->getId();
3
      if ($this->owner_id == $this->viewer_id) {
4
        $this->viewer = Meeting::VIEWER_ORGANIZER;
5
      } else {
6
        $this->viewer = Meeting::VIEWER_PARTICIPANT;
7
      }
8
    }

Вони налаштовують властивості $owner_id і $viewer в моделі Meeting.

Налаштування параметрів Meeting

Кожна зустріч, яку ви створюватимете матиме різні характеристики. Інколи вам захочеться обмежити можливість учасників пропонувати різний час і місця або останні деталі. А іноді вас це не хвилюватиме. Коли ми в кінці кінців створюємо шаблон Meeting для повторного використання для типових зустрічей, таких як ранкові ділові зустрічі за чашкою кави, шаблони в більшості випадків повинні зберігати також і налаштування користувачів. Як це реалізувати?

По-перше, я хотів би створити набір параметрів по замовчуванню для користувачів, які мають відношення до зустрічей, які вони створювали.

Далі я створю набір налаштувань MeetingSettings для кожної зустрічі. Коли зустріч створюється з нуля, вона перейматиме всі налаштування по замовчуванню від користувача, який її створює. Редагування налаштувань для індивідуальних зустрічей можна відкласти на пізніше.

В майбутньому, коли ми реалізуємо шаблони зустрічей, Meeting Template, ми додамо налаштування також і до шаблонів. Проте і це можна відкласти на потім.

Нижче наведено параметри, які ми хотіли б створити для початку:

  • Дозвіл учасникам додавати місця.
  • Дозвіл учасникам додавати дату і час.
  • Дозвіл учасникам вибирати місця.
  • Дозвіл учасникам вибрати дати і час.
  • Дозвіл учасникам вносити завершальні настройки зустрічі.

Оскільки через деякий час ми повертаємося до цієї статті (із-зі моєї відсутності по причині здоров'я), я торкнусь деяких деталей роботи.

Перш за все створимо міграцію налаштувань зустрічі, Meeting Settings migration:

1
$ ./yii migrate/create meeting_setting_table
2
Yii Migration Tool (based on Yii v2.0.7)
3
4
Create new migration '/Users/Jeff/Sites/mp/console/migrations/m160401_203412_meeting_setting_table.php'? (yes|no) [no]:yes
5
New migration created successfully.

Це створює файл міграції, який нам потрібно для написання коду, що будує таблицю даних, відповідно до нашої схеми:

1
<?php
2
use yii\db\Schema;
3
use yii\db\Migration;
4
5
class m160401_203412_meeting_setting_table extends Migration
6
{
7
  public function up()
8
   {
9
       $tableOptions = null;
10
       if ($this->db->driverName === 'mysql') {
11
           $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
12
       }
13
14
       $this->createTable('{{%meeting_setting}}', [
15
           'id' => Schema::TYPE_PK,
16
           'meeting_id' => Schema::TYPE_INTEGER.' NOT NULL',
17
           'participant_add_place' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
18
           'participant_add_date_time' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
19
           'participant_choose_place' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
20
           'participant_choose_date_time' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
21
           'participant_finalize' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
22
           'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',
23
           'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL',
24
       ], $tableOptions);
25
       $this->addForeignKey('fk_meeting_setting', '{{%meeting_setting}}', 'meeting_id', '{{%meeting}}', 'id', 'CASCADE', 'CASCADE');
26
   }
27
28
   public function down()
29
   {
30
       $this->dropForeignKey('fk_meeting_setting', '{{%meeting_setting}}');    
31
       $this->dropTable('{{%meeting_setting}}');
32
   }
33
}

Кожна зустріч по суті має рядок MeetingSettings з властивостями булевого типу для опцій різних учасників, які я показував вище.

Далі ми доручаємо Yii мігрувати і створити таблицю:

1
$ ./yii migrate/up
2
Yii Migration Tool (based on Yii v2.0.7)
3
4
Total 1 new migration to be applied:
5
    m160401_203412_meeting_setting_table
6
7
Apply the above migration? (yes|no) [no]:yes
8
*** applying m160401_203412_meeting_setting_table
9
    > create table {{%meeting_setting}} ... done (time: 0.010s)
10
    > add foreign key fk_meeting_setting: {{%meeting_setting}} (meeting_id) references {{%meeting}} (id) ... done (time: 0.011s)
11
*** applied m160401_203412_meeting_setting_table (time: 0.040s)
12
13
1 migration was applied.
14
Migrated up successfully.

Наш зовнішній ключ створює зв'язок між таблицями Meeting і MeetingSetting.

Далі ми скористаємося Yii's Gii для автоматичної генерації коду для перегляду і оновлення налаштувань. Для початку, я повернусь до http://localhost:8888/mp/index.php/gii/. Ми почнемо з генерації моделі:

Customizing Meeting View - Yiis Gii Model Generator for Meeting SettingCustomizing Meeting View - Yiis Gii Model Generator for Meeting SettingCustomizing Meeting View - Yiis Gii Model Generator for Meeting Setting

Потім ми згенеруємо код Create, Read, Update, Delete (CRUD):

Customizing Meeting View - The Gii CRUD GeneratorCustomizing Meeting View - The Gii CRUD GeneratorCustomizing Meeting View - The Gii CRUD Generator

Оскільки зараз нам не потрібен увесь цей код, Gii дозволяє нам обрати тільки потрібні нам функції: controllerview, _form and update:

Customizing Meeting View - Manually limiting files to overwriteCustomizing Meeting View - Manually limiting files to overwriteCustomizing Meeting View - Manually limiting files to overwrite

Gii показує список файлів, які створює на кожному кроці:

Customizing Meeting View - List of generated files by GiiCustomizing Meeting View - List of generated files by GiiCustomizing Meeting View - List of generated files by Gii

А як щодо налаштувань зустрічі користувача по замовчуванню? По суті, їх типові переваги?

Розширюємо можливості налаштування

Для цього ми додамо паралельні властивості налаштувань зустрічі в таблицю user_setting. Знову ж таки, ми створюємо міграцію:

1
$ ./yii migrate/create extend_user_setting_table
2
Yii Migration Tool (based on Yii v2.0.7)
3
4
Create new migration '/Users/Jeff/Sites/mp/console/migrations/m160401_210852_extend_user_setting_table.php'? (yes|no) [no]:yes
5
New migration created successfully.

Ось стовпці, які нам потрібно додати:

1
class m160401_210852_extend_user_setting_table extends Migration
2
{
3
  public function up()
4
  {
5
    $tableOptions = null;
6
    if ($this->db->driverName === 'mysql') {
7
        $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
8
    }    
9
    
10
    $this->addColumn('{{%user_setting}}','participant_add_place',Schema::TYPE_SMALLINT.' NOT NULL');
11
    $this->addColumn('{{%user_setting}}','participant_add_date_time',Schema::TYPE_SMALLINT.' NOT NULL');
12
    $this->addColumn('{{%user_setting}}','participant_choose_place',Schema::TYPE_SMALLINT.' NOT NULL');
13
    $this->addColumn('{{%user_setting}}','participant_choose_date_time',Schema::TYPE_SMALLINT.' NOT NULL');
14
    $this->addColumn('{{%user_setting}}','participant_finalize',Schema::TYPE_SMALLINT.' NOT NULL');
15
  }
16
17
  public function down()
18
  {
19
    $this->dropColumn('{{%user_setting}}','participant_finalize');
20
    $this->dropColumn('{{%user_setting}}','participant_choose_date_time');
21
    $this->dropColumn('{{%user_setting}}','participant_choose_place');
22
    $this->dropColumn('{{%user_setting}}','participant_add_date_time');
23
    $this->dropColumn('{{%user_setting}}','participant_add_place');
24
  }
25
}

Далі ми запускаємо міграцію:

1
$ ./yii migrate/up
2
Yii Migration Tool (based on Yii v2.0.7)
3
4
Total 1 new migration to be applied:
5
    m160401_210852_extend_user_setting_table
6
7
Apply the above migration? (yes|no) [no]:yes
8
*** applying m160401_210852_extend_user_setting_table
9
    > add column participant_add_place smallint NOT NULL to table {{%user_setting}} ... done (time: 0.012s)
10
    > add column participant_add_date_time smallint NOT NULL to table {{%user_setting}} ... done (time: 0.007s)
11
    > add column participant_choose_place smallint NOT NULL to table {{%user_setting}} ... done (time: 0.010s)
12
    > add column participant_choose_date_time smallint NOT NULL to table {{%user_setting}} ... done (time: 0.009s)
13
    > add column participant_finalize smallint NOT NULL to table {{%user_setting}} ... done (time: 0.009s)
14
*** applied m160401_210852_extend_user_setting_table (time: 0.061s)
15
16
1 migration was applied.
17
Migrated up successfully.

Замість того, щоб змушувати переписуватись нашу модель UserSetting.php в Gii, ми скористаємося опцією Gii diff.

Customizing Meeting View - Using Giis diff rather than overwritingCustomizing Meeting View - Using Giis diff rather than overwritingCustomizing Meeting View - Using Giis diff rather than overwriting

І звідти ми вручну виберемо нові доповнення до файлу і вставимо його:

Customizing Meeting View - Diff view to copy and paste necessary changesCustomizing Meeting View - Diff view to copy and paste necessary changesCustomizing Meeting View - Diff view to copy and paste necessary changes

Функціонально ми додамо таблицю налаштувань зустрічі до сторінки властивостей Update Your Settings:

Customizing Meeting View - User settings with the existing two tabsCustomizing Meeting View - User settings with the existing two tabsCustomizing Meeting View - User settings with the existing two tabs

Ми додали наступний код до /frontend/views/user-setting/_form.php для підтримки наших нових властивостей:

1
<div class="col-md-8">
2
         <!-- Nav tabs -->
3
         <ul class="nav nav-tabs" role="tablist">
4
           <li class="active"><a href="#general" role="tab" data-toggle="tab"><?= Yii::t('frontend','General Settings') ?></a></li>
5
           <li><a href="#preferences" role="tab" data-toggle="tab"><?= Yii::t('frontend','Meeting Preferences') ?></a></li>
6
           <li><a href="#photo" role="tab" data-toggle="tab"><?= Yii::t('frontend','Upload Photo') ?></a></li>
7
         </ul>
8
         <!-- Tab panes -->
9
         <div class="tab-content">
10
            ...
11
         </div>
12
           <div class="tab-pane vertical-pad" id="preferences">
13
             <?= $form->field($model, 'participant_add_place')->checkbox(['uncheck' =>  $model::SETTING_NO, 'checked' => $model::SETTING_YES]); ?> 
14
             <?= $form->field($model, 'participant_add_date_time')->checkbox(['uncheck' =>  $model::SETTING_NO, 'checked' => $model::SETTING_YES]); ?> 
15
             <?= $form->field($model, 'participant_choose_place')->checkbox(['uncheck' =>  $model::SETTING_NO, 'checked' => $model::SETTING_YES]); ?> 
16
             <?= $form->field($model, 'participant_choose_date_time')->checkbox(['uncheck' =>  $model::SETTING_NO, 'checked' => $model::SETTING_YES]); ?> 
17
             <?= $form->field($model, 'participant_finalize')->checkbox(['uncheck' =>  $model::SETTING_NO, 'checked' => $model::SETTING_YES]); ?> 
18
19
            </div> <!-- end of upload meeting-settings tab -->
20
            <div class="tab-pane vertical-pad" id="photo">    
21
        ...

Ось оновлена форма:

Customizing Meeting View - User settings with meeting preferencesCustomizing Meeting View - User settings with meeting preferencesCustomizing Meeting View - User settings with meeting preferences

Ініціалізація нових сесій зустрічей

Кожного разу, коли користувач створює нову зустріч, ми повинні завантажити її налаштування по замовчуванню і скопіювати їх в персональні налаштування зустрічі. initializeMeetingSetting викликається, коли створюється нова зустріч для наступного:

1
    public function initializeMeetingSetting($meeting_id,$owner_id) {
2
      // load meeting creator (owner) user settings to initialize meeting_settings

3
      $user_setting = UserSetting::find()->where(['user_id' => $owner_id])->one();
4
      $meeting_setting = new MeetingSetting();
5
      $meeting_setting->meeting_id = $meeting_id;
6
      $meeting_setting->participant_add_place=$user_setting->participant_add_place;
7
      $meeting_setting->participant_add_date_time=$user_setting->participant_add_date_time;
8
      $meeting_setting->participant_choose_place=$user_setting->participant_choose_place;
9
    $meeting_setting->participant_choose_date_time=$user_setting->participant_choose_date_time;
10
      $meeting_setting->participant_finalize=$user_setting->participant_finalize; 
11
      $meeting_setting->save();
12
    }

Коли у нас все в порядку з налаштуваннями зустрічі, ми можемо перейти до основної частини нашої роботи - налаштування режиму перегляду для організатора і учасників зустрічі.

Огляд режиму перегляду для організатора (власника)

Тепер давайте розглянемо стан режиму перегляду залежно від того, хто є переглядачем: учасник чи власник. Ось запрошення на зустріч, яке я нещодавно створив, щоб запросити мого друга Rob:

Customizing Meeting View - The Current Meeting ViewCustomizing Meeting View - The Current Meeting ViewCustomizing Meeting View - The Current Meeting View

Панель команд

Перш ніж активувати Send і Finalize, у вас повинна бути запрошена особа і хоча б одне місце зустрічі і час. Якщо у вас є більше, ніж одне місце зустрічі і час, щоб закінчити (finalize) налаштування зустрічі, вам потрібно обрати якийсь один варіант.

Кнопки скасування, Cancel (іконка "Х"), та редагування, Edit (іконка "ручка") також доступні для авторів зустрічі.

Люди

Для MVP ми обмежуємо запрошення на зустрічі до однієї особи. Отже, після того, як запросили одну людину, кнопка Add (іконка "+") стає недоступною.

Місце, дата і час зустрічі

Організатор зустрічі може додати місця, дату і час, Places та Date & Times, на сайт (максимум сім/зустріч), а також вказувати їх доступність і прийнятність. І, нарешті, коли місць більше, ніж одне, вони можуть вибрати, де саме і в який час відбудеться зустріч.

Примітки (Notes)

Організатор зустрічі завжди може додавати примітки. Примітки дозволяють організатору і учасникам спілкуватися один з одним.

У кінцевому рахунку, ми змістимо основну частину нашої роботи на покращення функціоналу AJAX, щоб після вибору організатором місця і часу зустрічі, кнопки Send і Finalize були доступними (або недоступними в деяких випадках).

Ось приклад зустрічі з двома можливими варіантами часу. Кнопка Finalize буде доступною, поки не буде обраний один варіант часу:

Customizing Meeting View - Another Meeting View Scenario Customizing Meeting View - Another Meeting View Scenario Customizing Meeting View - Another Meeting View Scenario

Коли вибір зроблено, нам потрібно активувати кнопку Finalize за допомогою AJAX без необхідності оновлювати сторінку.

Огляд режиму перегляду для учасника

Коли ми розглядаємо запрошення з точки зору учасника, ми з самого початку бачимо значно менше можливостей.

Customizing Meeting View - The Participant ViewCustomizing Meeting View - The Participant ViewCustomizing Meeting View - The Participant View

Учасник може скасувати (іконка "Х") свою участь, а також вказати, чи підходять для них місце і час зустрічі, проте вони можуть обрати остаточне місце зустрічі і завершити її налаштування (Finalize). Крім того, тепер колонки You і Them є активними. І панель учасника прихована, оскільки вона не потрібна.

Допустимо, зустріч була створена з налаштуваннями, які дозволяють учаснику вибирати місце, дату і час зустрічі, але не можливість завершити її налаштування. Це матиме наступний вигляд:

Customizing Meeting View - The Participant View with Participant ChoiceCustomizing Meeting View - The Participant View with Participant ChoiceCustomizing Meeting View - The Participant View with Participant Choice

Оскільки є тільки одне місце, Herkimer Coffee, в селекторі немає необхідності. Але, якщо є два можливих варіанта часу, ви можете бачити селектори Choose. Тим не менше, кнопки Finalize немає.

Виявилось, для підтримки всіх цих опцій знадобилося написати багато коду для оновлення системи. Проте це тільки початок, перед тим як зануритись в саме серце проекту - ux розкладу зустрічей. Я проведу вас через всі необхідні зміни.

Кодування вимог зустрічі

Реалізація налаштувань зустрічі

На панелі часу і місця зустрічі нам потрібно скористатися настройками, щоб визначити, чи потрібно відображати селектор вибору.  В режимі перегляду _panel.php, це виглядає ось так:

1
<table class="table">
2
     <thead>
3
     <tr class="small-header">
4
       <td></td>
5
       <td ><?=Yii::t('frontend','You') ?></td>
6
       <td ><?=Yii::t('frontend','Them') ?></td>
7
       <td >
8
         <?php
9
          if ($timeProvider->count>1 && ($isOwner || $model->meetingSettings->participant_choose_date_time)) echo Yii::t('frontend','Choose');
10
         ?>
11
        </td>
12
    </tr>
13
    </thead>
14
    <?= ListView::widget([ 
15
           'dataProvider' => $timeProvider, 
16
           'itemOptions' => ['class' => 'item'], 
17
           'layout' => '{items}',
18
           'itemView' => '_list', 
19
           'viewParams' => ['timeCount'=>$timeProvider->count,'isOwner'=>$isOwner,'participant_choose_date_time'=>$model->meetingSettings['participant_choose_date_time']],           
20
       ]) ?>
21
  </table>

Ми перевіряємо налаштування учасників і передаємо їх в якості параметра перегляду _list.php, що має наступний вигляд:

1
<td style>
2
      <?php
3
      if ($timeCount>1) {
4
        if ($model->status == $model::STATUS_SELECTED) {
5
            $value = $model->id;
6
        }    else {
7
          $value = 0;        
8
        }      
9
        if ($isOwner || $participant_choose_date_time) {
10
          // value has to match for switch to be on

11
          echo SwitchInput::widget([
12
              'type' => SwitchInput::RADIO,
13
              'name' => 'time-chooser',
14
              'items' => [
15
                  [ 'value' => $model->id],
16
              ],
17
              'value' => $value,
18
              'pluginOptions' => [  'size' => 'mini','handleWidth'=>60,'onText' => '<i class="glyphicon glyphicon-ok"></i>','offText'=>'<i class="glyphicon glyphicon-remove"></i>'],
19
              'labelOptions' => ['style' => 'font-size: 12px'],
20
          ]);            
21
        }
22
      }
23
      ?>
24
  </td>

Якщо переглядає організатор або учасник, якому дозволено обирати остаточний час, тоді вони побачать щось на зразок цього: можливість зробити вибір, Choose, в правій колонці:

Customizing Meeting View - The Choice Selector for Dates TimesCustomizing Meeting View - The Choice Selector for Dates TimesCustomizing Meeting View - The Choice Selector for Dates Times

Чи може переглядач відправити запрошення і завершити, Send і Finalize, зустріч

Я створив функції canSend() і canFinalize(), які загалом підтримують код і запити AJAX визначати активний стан кнопок Send і Finalize.

Ось canSend():

1
public function canSend($sender_id) {
2
       // check if an invite can be sent

3
       // req: a participant, at least one place, at least one time

4
       if ($this->owner_id == $sender_id       
5
        && count($this->participants)>0
6
        && count($this->meetingPlaces)>0
7
        && count($this->meetingTimes)>0
8
        ) {
9
         $this->isReadyToSend = true;
10
       } else {
11
         $this->isReadyToSend = false;
12
       }
13
       return $this->isReadyToSend;
14
      }

Організатор не може відправити запрошення на зустріч, поки не буде учасників, місця і часу.

Ось canFinalize():

1
public function canFinalize($user_id) {
2
        $this->isReadyToFinalize = false;
3
        // check if meeting can be finalized by viewer

4
        // check if overall meeting state can be sent by owner

5
         if (!$this->canSend($this->owner_id)) return false;
6
          $chosenPlace = false;
7
          if (count($this->meetingPlaces)==1) {
8
            $chosenPlace = true;
9
          } else {
10
            foreach ($this->meetingPlaces as $mp) {
11
              if ($mp->status == MeetingPlace::STATUS_SELECTED) {
12
                $chosenPlace = true;
13
                break;
14
              }
15
            }
16
          }
17
          $chosenTime = false;
18
          if (count($this->meetingTimes)==1) {
19
            $chosenTime = true;
20
          } else {
21
            foreach ($this->meetingTimes as $mt) {
22
              if ($mt->status == MeetingTime::STATUS_SELECTED) {
23
                  $chosenTime = true;
24
                  break;
25
              }                
26
            }
27
          }
28
          if ($this->owner_id == $user_id || 
29
          $this->meetingSettings->participant_finalize) {
30
            if ($chosenPlace && $chosenTime) {
31
              $this->isReadyToFinalize = true;              
32
            }
33
          }                    
34
        return $this->isReadyToFinalize;
35
      } 

Це перш за все перевіряє, чи може бути надіслано запрошення. Якщо ні, зустріч не можна завершити. Далі він перевіряє, чи були обрані місце і час. А потім він перевіряє, чи є переглядач організатором зустрічі, або ж дозволяє учаснику завершити сесію.

В принципі, коли  зміни внесено, ви побачите зміну стану кнопок Send і Finalize.

Customizing Meeting View - The Command Bar with Send and FinalizeCustomizing Meeting View - The Command Bar with Send and FinalizeCustomizing Meeting View - The Command Bar with Send and Finalize

У view.php, я включив JavaScript, щоб підтримати оновлення AJAX стану кнопок Send і Finalize, коли користувачі змінюють налаштування своїх зустрічей. Коли вибір місця і часу зроблено, викликаються refreshSend() і refreshFinalize() і кнопки змінюються відповідно.

1
<?php
2
if (isset(Yii::$app->params['urlPrefix'])) { 
3
  $urlPrefix = Yii::$app->params['urlPrefix'];
4
  } else {
5
    $urlPrefix ='';
6
  }
7
$script = <<< JS
8
function refreshSend() {
9
  $.ajax({
10
     url: '$urlPrefix/meeting/cansend',   
11
     data: {id: $model->id, 'viewer_id': $viewer},
12
     success: function(data) {
13
       if (data)
14
         $('#actionSend').removeClass("disabled");
15
        else 
16
        $('#actionSend').addClass("disabled");
17
       return true;
18
     }
19
  });
20
}
21
22
function refreshFinalize() {
23
  $.ajax({
24
     url: '$urlPrefix/meeting/canfinalize',   
25
     data: {id: $model->id, 'viewer_id': $viewer},
26
     success: function(data) {
27
       if (data)
28
         $('#actionFinalize').removeClass("disabled");
29
        else 
30
        $('#actionFinalize').addClass("disabled");
31
       return true;
32
     }
33
  });
34
}
35
36
JS;
37
$position = \yii\web\View::POS_READY;
38
$this->registerJs($script, $position);
39
?>

Огляд статусу вибору місця і часу

В даному інтерфейсі ми показуємо вибір місця і часу користувача в лівій або першій колонці. Коли переглядають учасники, потрібно кастомізувати код:

Customizing Meeting View - The You and Them Columns for Selection DataCustomizing Meeting View - The You and Them Columns for Selection DataCustomizing Meeting View - The You and Them Columns for Selection Data

Для підтримки відображення різних даних в колонках You і Them для Times і Places, файли meeting-time і meeting-place _list.php потрібно оновити, щоб визначити в динаміці, які дані відображаються:

1
<td style>
2
    <?php
3
       if ($isOwner) {
4
         showTimeOwnerStatus($model,$isOwner);
5
       } else {
6
         showTimeParticipantStatus($model,$isOwner);
7
       }
8
    ?>
9
  </td>
10
  <td style>
11
      <?php
12
        if (!$isOwner) {
13
           showTimeOwnerStatus($model,$isOwner);
14
         } else {
15
           showTimeParticipantStatus($model,$isOwner);
16
         }
17
      ?>
18
  </td>

На даний момент я помістив ці функції в перегляд _panel.php, який викликає calls _list.php, оскільки вони покладаються на включений в контекст віджет SwitchInput:

1
<?php
2
use \kartik\switchinput\SwitchInput;
3
4
  function showTimeOwnerStatus($model,$isOwner) {
5
    foreach ($model->meetingTimeChoices as $mtc) {
6
      if ($mtc->user_id == $model->meeting->owner_id) {
7
          if ($mtc->status == $mtc::STATUS_YES)
8
            $value = 1;
9
          else
10
            $value =0;
11
            echo SwitchInput::widget([
12
            'type' => SwitchInput::CHECKBOX,              
13
            'name' => 'meeting-time-choice',
14
            'id'=>'mtc-'.$mtc->id,
15
            'value' => $value,
16
            'disabled' => !$isOwner,
17
            'pluginOptions' => ['size' => 'mini','onText' => '<i class="glyphicon glyphicon-ok"></i>','offText'=>'<i class="glyphicon glyphicon-remove"></i>','onColor' => 'success','offColor' => 'danger',],
18
            ]);          
19
      }
20
    }
21
  }
22
23
  function showTimeParticipantStatus($model,$isOwner) {
24
    foreach ($model->meetingTimeChoices as $mtc) {
25
      if (count($model->meeting->participants)==0) break;
26
      if ($mtc->user_id == $model->meeting->participants[0]->participant_id) {
27
          if ($mtc->status == $mtc::STATUS_YES)
28
            $value = 1;
29
          else if ($mtc->status == $mtc::STATUS_NO)
30
            $value =0;
31
          else if ($mtc->status == $mtc::STATUS_UNKNOWN)
32
            $value =-1;
33
          echo SwitchInput::widget([
34
            'type' => SwitchInput::CHECKBOX,          
35
            'name' => 'meeting-time-choice',
36
            'id'=>'mtc-'.$mtc->id,
37
            'tristate'=>true,
38
            'indeterminateValue'=>-1,
39
            'indeterminateToggle'=>false,
40
            'disabled'=>$isOwner,
41
            'value' => $value,
42
            'pluginOptions' => ['size' => 'mini','onText' => '<i class="glyphicon glyphicon-ok"></i>','offText'=>'<i class="glyphicon glyphicon-remove"></i>','onColor' => 'success','offColor' => 'danger',],
43
        ]);          
44
      }
45
    }  
46
  }
47
?>

Подальші налаштування

На кінець, потрібно зробити ще багато покращень коду. В пункті місця, я роблю виклики AJAX до серверу два чи три рази, проте я міг би зробити це більш ефективно в одному запиті. В інших місцях я можу зробити більш локальні зміни за допомогою JavaScript. Також було б чудово покращити інтерфейс, а значить, відповідно і код. проте з точки зору функціональності, наша сьогоднішня робота відображає більшу частину того, що необхідно в відношенні MVP.

Що далі?

Коли налаштування зустрічі і вимоги до режиму перегляду для організаторів і учасників на своїх місцях, я готовий відправити перше запрошення. Наступна стаття розповідатиме про те, як надіслати запрошення учасникам на email, відобразити контент, функціональні посилання команд, а також питання дозволу для користувачів, які ще не зареєструвались. Слідкуйте за нашими очікуваними статтями серії Building Your Startup With PHP series - це буде щось неймовірно захопливе!

Будь ласка, не вагайтесь і сміливо задавайте питання та залишайте коментарі нижче; загалом, я приймаю участь в обговореннях. Ви також можете зв'язатися зі мною в Twitter @reifman.

Посилання по темі

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.