Spanish (Español) translation by Cristian Marroquin (you can also view the original English article)



Este tutorial es parte de la serie Construyendo Tu Startup Con PHP en Envato Tuts+. En estas series, Te guiaré en el proceso de lanzar una startup desde el concepto hasta la realidad usando mi aplicación Meeting Planner como ejemplo de la vida real. En cada paso, estaré colocando el código de Meeting Planner como ejemplos de código abierto de los cuales puedes aprender. También abordaré problemas relacionados con las startup conforme vayan surgiendo.
Aprovechando Bootstrap, Ajax, y jQuery
Durante nuestra serie startup, Meeting Planner y Simple Planner han evolucionado en gran medida. Recientemente, He estado tratando de afinar detalles de algunas áreas para hacer que el uso del servicio para programar reuniones tenga mayor grado de facilidad.
Si recuerdas nuestro episodio Construye Tu Startup: Formularios para Agendar Dinámicos con Ajax (Envato Tuts+), Tu sabes que tan útiles pueden ser Ajax y jQuery para la usabilidad. Haciendo la programación interactiva con Ajax ha transformado la usabilidad del sitio.
Lo siguiente, quise mejorar un punto débil que he encontrado en la utilización del servicio. Francamente, consume mucho tiempo cuando envías invitaciones para sugerir múltiples opciones de fechas y horarios. Cada vez que envié una invitación para una reunión para mi propia startup, tenia que crear dos o tres opciones de fecha/horario manualmente — y eso era algo molesto.
En el episodio de hoy, Voy a guiarte a través de como hice simple el programar una reunión con muchas fechas y horarios relacionados en un solo paso. Específicamente,voy a describir como usé bootstrap, Ajax y jQuery para resolver el problema de elegir fechas y horarios.
Bootstrap hizo fácil diseñar la característica para el escritorio, tablet y dispositivos móviles, y Ajax y jQuery lo hicieron rapido e interactivo.
Si no has probado aun Meeting Planner o Simple Planner, adelante y programa tu primera reunión. Busca el tema de este tutorial mientras eliges tus opciones de fechas y horarios.
Yo participo en los hilos de comentarios de abajo, así que dime que piensas También puedes encontrarme en Twiiter @lookahead_io. Estoy especialmente interesado si quieres sugerir nuevas características o temas para futuros tutoriales.
Como un recordatorio, todo el código de Meeting Planner esta escrito en el Framework de PHP Yii2. Si quieres aprender mas acerca de Yii2, revisa nuestra series paralela Programando con Yii2.
Diseñando la Solución



Usando Meeting Planner con el tiempo, regularmente hubiese querido una forma de crear una serie de datos y horarios de forma consecutiva, como los siguientes tres dias a la 8:30 am o las siguientes tres semanas el miércoles a las 7 pm. Eso hace mas fácil ponerse de acuerdo con la gente cuando tienes múltiples opciones para cuando te vas a reunir.
Mientras ahondaba en profundidad el pulir la interfaz de usuario, Finalmente tuve mi propio tiempo para enfocarme en este problema. Antes de escribir código alguno, Yo decidí vagamente esbozar lo que quería.
Decidí crear una cantidad repetitiva, tales como las próximas tres o cinco, y una unidad repetitiva, como horas, días, o semanas.
En otras palabras, digamos que estoy invitando al asistente de edición Tom McFarlin a un café y quiero ofrecerle cualquiera de las mañanas delos próximos tres días, entonces elijo dos y días para repetir después de elegir el día.
Manteniendolo Simple
No quería que la gente siempre se enfrentara con un formulario complejo solo para programar una reunión, así que separé la característica de repetición de fecha y hora con un enlace de opciones avanzadas que se muestra abajo. Tocando o dando clic en este enlace abre el formulario que se muestra debajo:



Comenzando Escribir Código
Para diseñar el formulario y que funcione tanto con el escritorio y dispositivos móviles, Aproveché Bootstrap. Esencialmente, Creé varas filas para el formulario con varias columnas de ancho que se colapsa en móviles. Vamos a ver.
Mucho de la magia de HTML sucede aquí, en /frontend/views/meeting-time/_form.php. Primero, aquí esta la fila con la Fecha, Hora, Duración y el enlace de opciones avanzadas:
<div class="meeting-time-form"> <div class="row"> <div class="col-xs-12 col-md-4 col-lg-3"> <?php $form = ActiveForm::begin();?> <?= Html::activeHiddenInput($model, 'url_prefix',['value'=>MiscHelpers::getUrlPrefix(),'id'=>'url_prefix']); ?> <?= Html::activeHiddenInput($model, 'tz_dynamic',['id'=>'tz_dynamic']); ?> <?= Html::activeHiddenInput($model, 'tz_current',['id'=>'tz_current']); ?> <strong><?php echo Yii::t('frontend','Date') ?></strong> <div class="datetimepicker-width"> <?= DateTimePicker::widget([ 'model' => $model, 'attribute' => 'start', 'template' => '{input}{button}', //'language' => 'en', 'size' => 'ms', 'clientOptions' => [ 'autoclose' => true, 'format' => 'M d, yyyy', 'todayBtn' => true, //'pickerPosition' => 'bottom-left', 'startView'=>2, 'minView'=>2, // to do - format three day ahead 'initialDate'=> Date('Y-m-d',time()+3600*72), ] ]);?></div> <p></p> </div> <div class="col-xs-12 col-md-4 col-lg-3"> <strong><?php echo Yii::t('frontend','Time') ?></strong> <div class="datetimepicker-width"> <?= DateTimePicker::widget([ 'model' => $model, 'attribute' => 'start_time', 'template' => '{input}{button}', //'language' => 'en', 'size' => 'ms', 'clientOptions' => [ 'autoclose' => true, 'format' => 'H:ii p', 'todayBtn' => false, 'minuteStep'=> 15, 'showMeridian'=>true, //'pickerPosition' => 'bottom-left', 'startView'=>1, 'minView'=>0, 'maxView'=>1, // to do - format one day ahead //'initialDate'=> Date('Y-m-d'), // $( "th.switch" ).text( "Pick the time" ); ] ]);?> </div> <p></p> </div> <div class="col-xs-6 col-md-2 col-lg-2"> <?php $durationList = [1=>'1 hour',2=>'2 hours',3=>'3 hours',4=>'4 hours',5=>'5 hours',6=>'6 hours',12=>'12 hours',24=>'24 hours',48=>'48 hours',72=>'72 hours']; echo $form->field($model, 'duration',['options' => ['id'=>'duration','class' => 'duration-width' ]]) ->dropDownList( $durationList, // Flat array ('id'=>'label') ['prompt'=>'select a duration'] // options ); ?> </div> <div class="col-xs-6 col-md-2 col-lg-2" style="margin-top:3em;"> <?= Html::a(Yii::t('frontend','advanced options'),'javascript:void(0);', ['onclick'=>'toggleTimeAdvanced();']);?> </div> </div>
Al usar exitosamente dimensiones de columnas como estas en Bootstrap. la fila se extiende en el escritorio (como se ve abajo) y el mismo se colapsa en tres filas en móvil (visto arriba):
<div class="col-xs-12 col-md-4 col-lg-3"> <!-- Date --> ... <div class="col-xs-12 col-md-4 col-lg-3"> <!-- Time --> ... <div class="col-xs-6 col-md-2 col-lg-2"> <!-- Duration --> ... <div class="col-xs-6 col-md-2 col-lg-2" style="margin-top:3em;"> <!-- Advanced options --> ...



El jQuery toggleTimeAdvanced()
para el enlace de opciones avanzadas abre el formulario de repetición al remover la clase hidden
:
function toggleTimeAdvanced() { if ($('#timeAdvanced').hasClass('hidden')) { $('#timeAdvanced').removeClass('hidden'); } else { $('#timeAdvanced').addClass('hidden'); $("select#meetingtime-repeat_quantity").prop('selectedIndex', 0); }
Nota: Todo el jQuery lo puedes encontrar en /frontend/web/js/meeting.js.
Esto también reinicia a cero la configuración de repetición cuando se cierra — esto fue una decisión de diseño para prevenir que se creen duplicados si la gente cierra el formulario de avanzadas.
Aquí esta el sub-formulario timeAdvanced
:
<div class="row hidden" id="timeAdvanced"> <div class="col-xs-12 col-md-2 col-lg-2"> <?php $repeat_quantity = [0=>'no repeating',1=>'1 additional option', 2=>'2 additional options',3=>'3 additional options', 4=>'4 additional options',5=>'5 additional options']; echo $form->field($model, 'repeat_quantity',['options' => ['id'=>'repeat_quantity','class' => 'repeat-width' ]])->label('Add') ->dropDownList( $repeat_quantity , ['options'=>['1'=>['Selected'=>true]]] ); ?> </div> <div class="col-xs-12 col-md-6 col-lg-6"> <?php $repeat_unit = ['hour'=>'successive hour e.g. 9 am, 10 am and 11 am', 'day'=>'successive day e.g. Monday, Tuesday & Wednesday', 'week'=>'successive week e.g. next Friday & Friday after']; echo $form->field($model, 'repeat_unit',['options' => ['id'=>'repeat_unit','class' => 'repeat-width' ]])->label('On each') ->dropDownList( $repeat_unit ); ?> </div> </div>
El Bootstrap que usé aparece en una fila en escritorios y en dos filas en dispositivos móviles.
<div class="col-xs-12 col-md-2 col-lg-2"> <!-- repeat quantity --> <div class="col-xs-12 col-md-6 col-lg-6"> <!-- repeat unit -->
Aquí esta como se ve al agregar 3 opciones adicionales para cada dia consecutivo a las 9 am:



A continuación, Actualicé la función addTime()
para capturar y enviar los campos repeat_quantity
y repeat_unit
al controlador basado en PHP:
function addTime(id) { start_time = $('#meetingtime-start_time').val(); start = $('#meetingtime-start').val(); duration = $('#meetingtime-duration').val(); repeat_quantity = $('#meetingtime-repeat_quantity').val(); repeat_unit = $('#meetingtime-repeat_unit').val(); if (start_time =='' || start=='') { displayAlert('timeMessage','timeMsg2'); return false; } // ajax submit subject and message $.ajax({ url: $('#url_prefix').val()+'/meeting-time/add', data: { id: id, start_time: encodeURIComponent(start_time), start:encodeURIComponent(start), duration:encodeURIComponent(duration), repeat_quantity:encodeURIComponent(repeat_quantity), repeat_unit:encodeURIComponent(repeat_unit), }, success: function(data) { loadTimeChoices(id); insertTime(id); displayAlert('timeMessage','timeMsg1'); return true; } });
Las Startups son difíciles en el sentido que siempre estas corriendo para que las nuevas características estén echas. Por ejemplo, alguien (probablemente yo ya que soy el único programador) nunca ha transferido la duración seleccionada; así que, agregué eso también. Hasta el dia de hoy, todas las reuniones eran de 1 hora sin importar lo que los usuarios solicitaran. dicho lo suficiente. #startuplife.
Entonces, me cambié al código MVC basado en Yii Framework en mi /frontend/controllers/MeetingTimeController.php. Debajo, puedes ver el método AJAX actionAdd
que responde a la solicitud de jQuery:
public function actionAdd($id,$start,$start_time,$duration=1,$repeat_quantity=0,$repeat_unit='hour') { Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; $timezone = MiscHelpers::fetchUserTimezone(Yii::$app->user->getId()); date_default_timezone_set($timezone); $cnt=0; while ($cnt<=$repeat_quantity) { $model = new MeetingTime(); $model->start = urldecode($start); $model->start_time = urldecode($start_time); if (empty($model->start)) { $model->start = Date('M d, Y',time()+3*24*3600); } $model->tz_current = $timezone; $model->duration = $duration; $model->meeting_id= $id; $model->suggested_by= Yii::$app->user->getId(); $model->status = MeetingTime::STATUS_SUGGESTED; $selected_time = date_parse($model->start_time); if ($selected_time['hour'] === false) { $selected_time['hour'] =9; $selected_time['minute'] =0; } // convert date time to timestamp $model->start = strtotime($model->start) + $selected_time['hour']*3600+ $selected_time['minute']*60; if ($cnt>0) { switch ($repeat_unit) { case 'hour': $model->start+=($cnt*3600); break; case 'day': $model->start+=($cnt*24*3600); break; case 'week': $model->start+=($cnt*7*24*3600); break; } } $model->end = $model->start + (3600*$model->duration); $model->save(); $cnt+=1; } return true; }
Básicamente, Creé un bucle usando un contador, $cnt
, para incrementar las opciones de tiempo de inicio y de fin de la Reunión con $repeat_unit
, ej. horas, días, o semanas:
if ($cnt>0) { switch ($repeat_unit) { case 'hour': $model->start+=($cnt*3600); break; case 'day': $model->start+=($cnt*24*3600); break; case 'week': $model->start+=($cnt*7*24*3600); break; } } $model->end = $model->start + (3600*$model->duration);
Entonces aquí están mis resultados agregando tres espacios de tiempo adicionales cada día a las 9:00 AM:



Así que ahora, es mas fácil programar reuniones con la gente y ofrecerles varias fechas y horarios sucesivos como opciones para reunirse.
En conclusión
Espero que esto haya sido útil para que veas como se puede usar Bootstrap para crear mejores formularios y que se puede combinar con Ajax y jQuery para construir una experiencia simple e interactiva para tus usuarios.
Si no lo hiciste anteriormente, prueba programando una reunión en Meeting Planner con opciones repetitivas de fecha/hora y déjame saber lo que piensas.
¿Tienes tus propias opiniones? ¿Ideas? ¿sugerencias? Siempre puedes encontrarme en Twitter @lookahead_io directamente. Mira lospróximos tutoriales aquí en la serie Construye Tu Startup Con PHP.
En las próximas semanas, Voy a continuar puliendo la experiencia de usuario para hacer el servicio tan fácil de usar como sea posible. Por ejemplo, puedes notar que las notas de la reunión están ahora en su propia pestaña:



Y, para eliminar la confusión que estaban teniendo las personas entre la disposición de la columna de interruptores si/no y la segunda columna de selección de lugar final, separé esta en un sub panel de botones inferior, Finalizar el horario. Solamente organizadores y participantes designados como organizadores ven este panel inferior, simplificando la vista común para los participantes típicos.



Bootstrap, jQuery y Ajax están atados parcial o completamente en construir ambas características también.
Espero que por ahora en las series, estés teniendo tus propias ideas de startup y pensando sobre escribir algo de código. Mantente sintonizado para aprender mas sobre como construyo y lanzo la mía.