Agregar, editar y borrar comentarios

This commit is contained in:
Juan Pablo Vial
2024-07-04 18:09:25 -04:00
parent fc543729d2
commit a428aeebe1
7 changed files with 358 additions and 24 deletions

View File

@ -27,7 +27,10 @@ $app->group('/ventas', function($app) {
}); });
$app->group('/venta/{venta_id}', function($app) { $app->group('/venta/{venta_id}', function($app) {
$app->get('/unidades[/]', [Ventas::class, 'unidades']); $app->get('/unidades[/]', [Ventas::class, 'unidades']);
$app->get('/comentarios[/]', [Ventas::class, 'comentarios']); $app->group('/comentarios', function($app) {
$app->post('/add[/]', [Ventas::class, 'addComentario']);
$app->get('[/]', [Ventas::class, 'comentarios']);
});
$app->group('/escritura', function($app) { $app->group('/escritura', function($app) {
$app->post('/add[/]', [Ventas\Escrituras::class, 'add']); $app->post('/add[/]', [Ventas\Escrituras::class, 'add']);
}); });

View File

@ -0,0 +1,8 @@
<?php
use Incoviba\Controller\API\Ventas\Comentarios;
$app->group('/comentario/{comentario_id}', function($app) {
$app->post('/edit[/]', [Comentarios::class, 'edit']);
$app->delete('/remove[/]', [Comentarios::class, 'remove']);
//$app->get('[/]', [Comentarios::class, 'get']);
});

View File

@ -3,9 +3,9 @@
COMENTARIOS COMENTARIOS
</div> </div>
<div class="right aligned column"> <div class="right aligned column">
<a href="javascript: addComment()" style="color: inherit;"> <button class="ui icon button" style="background: none; color: inherit; padding: 0;" id="add_comentario_button">
<i class="plus icon"></i> <i class="plus icon"></i>
</a> </button>
</div> </div>
</div> </div>
<div class="ui segment"> <div class="ui segment">
@ -13,37 +13,199 @@
<tbody id="comentarios"></tbody> <tbody id="comentarios"></tbody>
</table> </table>
</div> </div>
<div class="ui modal" id="addComment">
<div class="header">
Agregar Comentario
</div>
<div class="content">
<form class="ui form">
<div class="three wide field">
<label>Fecha</label>
<div class="ui calendar" id="fecha">
<div class="ui icon input">
<input type="text" placeholder="Fecha">
<i class="calendar icon"></i>
</div>
</div>
</div>
<div class="field">
<label>Comentario</label>
<textarea id="comentario" rows="2"></textarea>
</div>
</form>
</div>
<div class="actions">
<div class="ui black deny button">
Cancelar
</div>
<div class="ui positive right labeled icon button">
Agregar
<i class="checkmark icon"></i>
</div>
</div>
</div>
<div class="ui modal" id="editComment">
<div class="header">
Edit Comentario
</div>
<div class="content">
<form class="ui form">
<input type="hidden" name="id" />
<div class="three wide field">
<label>Fecha</label>
<div class="ui calendar" id="fechaEdit">
<div class="ui icon input">
<input type="text" placeholder="Fecha">
<i class="calendar icon"></i>
</div>
</div>
</div>
<div class="field">
<label>Comentario</label>
<textarea id="comentarioEdit" rows="2"></textarea>
</div>
</form>
</div>
<div class="actions">
<div class="ui black deny button">
Cancelar
</div>
<div class="ui positive right labeled icon button">
Editar
<i class="checkmark icon"></i>
</div>
</div>
</div>
@push('page_scripts') @push('page_scripts')
<script type="text/javascript"> <script type="text/javascript">
class Comentario class Comentario {
{ id
fecha fecha
texto texto
constructor({fecha, texto}) constructor({id, fecha, texto})
{ {
this.id = id
this.fecha = new Date(fecha + 'T00:00:00') this.fecha = new Date(fecha + 'T00:00:00')
this.texto = texto this.texto = texto
} }
draw(dateFormatter) draw(dateFormatter)
{ {
return $('<tr></tr>').append( return [
$('<td></td>').html(dateFormatter.format(this.fecha)) '<tr>',
).append( `<td class="collapsing">${dateFormatter.format(this.fecha)}</td>`,
$('<td></td>').html(this.texto) `<td>${this.texto}</td>`,
).append( '<td class="right aligned">',
$('<td></td>').addClass('right aligned').append( `<button class="ui tiny tertiary icon button editComentario" data-id="${this.id}">`,
$('<a></a>').attr('href', 'javascript: removeComment();').append( '<i class="edit icon"></i>',
$('<i></i>').addClass('minus icon') '</button>',
) `<button class="ui tiny tertiary red icon button removeComentario" data-id="${this.id}">`,
) '<i class="minus icon"></i>',
) '</button>',
'</td>',
'</tr>'
].join("\n")
}
}
class AddModal {
props
constructor({id}) {
this.props = {
id
}
$(this.props.id).modal({
onApprove: () => {
this.approve()
}
})
const cdo = structuredClone(calendar_date_options)
$(this.props.id).find('.ui.calendar').calendar(cdo)
this.hide()
}
approve() {
const fecha = $(this.props.id).find('#fecha').calendar('get date')
const fechaString = [fecha.getFullYear(), fecha.getMonth()+1, fecha.getDate()].join('-')
const comentario = $(this.props.id).find('#comentario').val()
const uri = '{{$urls->api}}/venta/{{$venta->id}}/comentarios/add'
const body = new FormData()
body.append('fecha', fechaString)
body.append('texto', comentario)
fetchAPI(uri, {method: 'post', body}).then(response => {
if (!response) {
return
}
return response.json().then(data => {
if (data.added) {
comentarios.comentarios.push(new Comentario(data.comentario))
comentarios.draw().comentarios()
}
})
})
}
show() {
const modal = $(this.props.id)
modal.find('form').trigger('reset')
modal.modal('show')
}
hide() {
const modal = $(this.props.id)
modal.modal('hide')
}
}
class EditModal {
props
constructor({id}) {
this.props = {
id
}
$(this.props.id).modal({
onApprove: () => {
this.approve()
}
})
const cdo = structuredClone(calendar_date_options)
$(this.props.id).find('.ui.calendar').calendar(cdo)
this.hide()
}
approve() {
const id = $(this.props.id).find("[name='id']").val()
const fecha = $(this.props.id).find('#fechaEdit').calendar('get date')
const fechaString = [fecha.getFullYear(), fecha.getMonth()+1, fecha.getDate()].join('-')
const comentario = $(this.props.id).find('#comentarioEdit').val()
const uri = `{{$urls->api}}/ventas/comentario/${id}/edit`
const body = new FormData()
body.append('fecha', fechaString)
body.append('texto', comentario)
fetchAPI(uri, {method: 'post', body}).then(response => {
if (!response) {
return
}
return response.json().then(data => {
if (data.edited) {
const idx = comentarios.comentarios.findIndex(comentario => comentario.id === data.comentario_id)
comentarios.comentarios[idx] = new Comentario(data.comentario)
comentarios.draw().comentarios()
}
})
})
}
show() {
const modal = $(this.props.id)
modal.modal('show')
}
hide() {
const modal = $(this.props.id)
modal.modal('hide')
} }
} }
const comentarios = { const comentarios = {
comentarios: [], comentarios: [],
id: '', id: '',
modals: {
add: null,
edit: null
},
fetch: function() { fetch: function() {
return { return {
comentarios: () => { comentarios: () => {
@ -60,6 +222,7 @@
this.comentarios.push(new Comentario(settings)) this.comentarios.push(new Comentario(settings))
}) })
this.draw().comentarios() this.draw().comentarios()
}) })
} }
} }
@ -73,11 +236,41 @@
this.comentarios.forEach(comentario => { this.comentarios.forEach(comentario => {
body.append(comentario.draw(dateFormatter)) body.append(comentario.draw(dateFormatter))
}) })
$('.editComentario').on('click', event => {
const id = $(event.currentTarget).data('id')
const comentario = this.comentarios.find(comentario => comentario.id === id)
const modal = this.modals.edit
const fecha = new Date(comentario.fecha)
$(modal.props.id).find("[name='id']").val(id)
$(modal.props.id).find('#fechaEdit').calendar('set date', fecha)
$(modal.props.id).find('#comentarioEdit').val(comentario.texto)
modal.show()
})
$('.removeComentario').click(event => {
const id = $(event.currentTarget).data('id')
const uri = `{{$urls->api}}/ventas/comentario/${id}/remove`
fetchAPI(uri, {method: 'delete'}).then(response => {
if (!response) {
return
}
return response.json().then(data => {
if (data.removed) {
this.comentarios = this.comentarios.filter(comentario => comentario.id !== id)
this.draw().comentarios()
}
})
})
})
} }
} }
}, },
setup: function(id) { setup: function(id) {
this.id = id this.id = id
this.modals.add = new AddModal({id: '#addComment'})
this.modals.edit = new EditModal({id: '#editComment'})
$('#add_comentario_button').click(() => {
this.modals.add.show()
})
this.fetch().comentarios() this.fetch().comentarios()
} }
} }

View File

@ -12,6 +12,7 @@ use Incoviba\Controller\withRedis;
use Incoviba\Model; use Incoviba\Model;
use Incoviba\Repository; use Incoviba\Repository;
use Incoviba\Service; use Incoviba\Service;
use Psr\Log\LoggerInterface;
class Ventas extends Controller class Ventas extends Controller
{ {
@ -190,7 +191,7 @@ class Ventas extends Controller
$output['total'] = count($output['comentarios']); $output['total'] = count($output['comentarios']);
} catch (EmptyRedis) { } catch (EmptyRedis) {
try { try {
$comentarios = $comentarioRepository->fetchByVenta($venta->id); $comentarios = $comentarioRepository->fetchActiveByVenta($venta->id);
$output['total'] = count($comentarios); $output['total'] = count($comentarios);
$output['comentarios'] = $comentarios; $output['comentarios'] = $comentarios;
$this->saveRedis($redisService, $redisKey, $output['comentarios']); $this->saveRedis($redisService, $redisKey, $output['comentarios']);
@ -337,4 +338,36 @@ class Ventas extends Controller
} catch (EmptyResult) {} } catch (EmptyResult) {}
return $this->withJson($response, $output); return $this->withJson($response, $output);
} }
public function addComentario(ServerRequestInterface $request, ResponseInterface $response,
Repository\Venta $ventaRepository, Repository\Venta\Comentario $comentarioRepository,
Service\Redis $redisService,
int $venta_id): ResponseInterface
{
$body = $request->getParsedBody();
$output = [
'venta_id' => $venta_id,
'input' => $body,
'comentario' => null,
'added' => false
];
try {
$venta = $ventaRepository->fetchById($venta_id);
$body['venta'] = $venta->id;
$body['estado'] = true;
$filteredData = $comentarioRepository->filterData($body);
try {
$comentarioRepository->fetchByVentaAndFechaAndTexto($venta_id, new DateTimeImmutable($filteredData['fecha']), $filteredData['texto']);
} catch (EmptyResult) {
$redisKey = "comentarios:venta:{$venta_id}";
$comentarios = $this->fetchRedis($redisService, $redisKey);
$comentario = $comentarioRepository->create($filteredData);
$output['comentario'] = $comentarioRepository->save($comentario);
$comentarios []= $comentario;
$this->saveRedis($redisService, $redisKey, $comentarios);
}
$output['added'] = true;
} catch (EmptyResult) {}
return $this->withJson($response, $output);
}
} }

View File

@ -0,0 +1,68 @@
<?php
namespace Incoviba\Controller\API\Ventas;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Incoviba\Common\Implement\Exception\EmptyResult;
use Incoviba\Controller\API\withJson;
use Incoviba\Controller\withRedis;
use Incoviba\Repository;
use Incoviba\Service;
class Comentarios
{
use withJson, withRedis;
public function edit(ServerRequestInterface $request, ResponseInterface $response,
Repository\Venta\Comentario $comentarioRepository,
Service\Redis $redisService, int $comentario_id): ResponseInterface
{
$output = [
'comentario_id' => $comentario_id,
'comentario' => null,
'edited' => false
];
$data = $request->getParsedBody();
try {
$comentario = $comentarioRepository->fetchById($comentario_id);
$filteredData = $comentarioRepository->filterData($data);
$comentario = $comentarioRepository->edit($comentario, $filteredData);
$redisKey = "comentarios:venta:{$comentario->venta->id}";
$comentarios = $this->fetchRedis($redisService, $redisKey);
$index = array_column(json_decode(json_encode($comentarios), true), 'id');
$idx = array_search($comentario->id, $index);
$comentarios[$idx] = $comentario;
$this->saveRedis($redisService, $redisKey, $comentarios);
$output['comentario'] = $comentario;
$output['edited'] = true;
} catch (EmptyResult) {}
return $this->withJson($response, $output);
}
public function remove(ServerRequestInterface $request, ResponseInterface $response,
Repository\Venta\Comentario $comentarioRepository, Service\Redis $redisService,
int $comentario_id): ResponseInterface
{
$output = [
'comentario_id' => $comentario_id,
'comentario' => null,
'removed' => false
];
try {
$comentario = $comentarioRepository->fetchById($comentario_id);
$output['comentario'] = $comentario;
$comentarioRepository->remove($comentario);
$redisKey = "comentarios:venta:{$comentario->venta->id}";
$comentarios = $this->fetchRedis($redisService, $redisKey);
$index = array_column(json_decode(json_encode($comentarios), true), 'id');
$idx = array_search($comentario->id, $index);
unset($comentarios[$idx]);
$this->saveRedis($redisService, $redisKey, $comentarios);
$output['removed'] = true;
} catch (EmptyResult) {}
return $this->withJson($response, $output);
}
}

View File

@ -3,9 +3,11 @@ namespace Incoviba\Model\Venta;
use DateTimeInterface; use DateTimeInterface;
use Incoviba\Common\Ideal; use Incoviba\Common\Ideal;
use Incoviba\Model\Venta;
class Comentario extends Ideal\Model class Comentario extends Ideal\Model
{ {
public Venta $venta;
public DateTimeInterface $fecha; public DateTimeInterface $fecha;
public string $texto; public string $texto;
public bool $activo; public bool $activo;
@ -13,6 +15,7 @@ class Comentario extends Ideal\Model
public function jsonSerialize(): mixed public function jsonSerialize(): mixed
{ {
return array_merge(parent::jsonSerialize(), [ return array_merge(parent::jsonSerialize(), [
'venta_id' => $this->venta->id,
'fecha' => $this->fecha->format('Y-m-d'), 'fecha' => $this->fecha->format('Y-m-d'),
'texto' => $this->texto, 'texto' => $this->texto,
'activo' => $this->activo 'activo' => $this->activo

View File

@ -6,10 +6,11 @@ use Incoviba\Common\Ideal;
use Incoviba\Common\Define; use Incoviba\Common\Define;
use Incoviba\Common\Implement; use Incoviba\Common\Implement;
use Incoviba\Model; use Incoviba\Model;
use Incoviba\Repository;
class Comentario extends Ideal\Repository class Comentario extends Ideal\Repository
{ {
public function __construct(Define\Connection $connection) public function __construct(Define\Connection $connection, protected Repository\Venta $ventaRepsitory)
{ {
parent::__construct($connection); parent::__construct($connection);
$this->setTable('comentario'); $this->setTable('comentario');
@ -18,6 +19,10 @@ class Comentario extends Ideal\Repository
public function create(?array $data = null): Define\Model public function create(?array $data = null): Define\Model
{ {
$map = (new Implement\Repository\MapperParser(['texto'])) $map = (new Implement\Repository\MapperParser(['texto']))
->register('venta', (new Implement\Repository\Mapper())
->setFunction(function($data) {
return $this->ventaRepsitory->fetchById($data['venta']);
}))
->register('fecha', new Implement\Repository\Mapper\DateTime('fecha')) ->register('fecha', new Implement\Repository\Mapper\DateTime('fecha'))
->register('estado', new Implement\Repository\Mapper\Boolean('estado', 'activo')); ->register('estado', new Implement\Repository\Mapper\Boolean('estado', 'activo'));
return $this->parseData(new Model\Venta\Comentario(), $data, $map); return $this->parseData(new Model\Venta\Comentario(), $data, $map);
@ -25,19 +30,40 @@ class Comentario extends Ideal\Repository
public function save(Define\Model $model): Define\Model public function save(Define\Model $model): Define\Model
{ {
$model->id = $this->saveNew( $model->id = $this->saveNew(
['fecha', 'texto', 'estado'], ['venta', 'fecha', 'texto', 'estado'],
[$model->fecha->format('Y-m-d'), $model->texto, $model->activo ? 1 : 0] [$model->venta->id, $model->fecha->format('Y-m-d'), $model->texto, $model->activo ? 1 : 0]
); );
return $model; return $model;
} }
public function edit(Define\Model $model, array $new_data): Define\Model public function edit(Define\Model $model, array $new_data): Define\Model
{ {
return $this->update($model, ['fecha', 'texto', 'estado'], $new_data); return $this->update($model, ['venta', 'fecha', 'texto', 'estado'], $new_data);
} }
public function fetchByVenta(int $venta_id): array public function fetchActiveByVenta(int $venta_id): array
{ {
$query = "SELECT * FROM `{$this->getTable()}` WHERE `venta` = ? AND `estado` = 1 ORDER BY `fecha` DESC"; $query = $this->connection->getQueryBuilder()
->select()
->from($this->getTable())
->where('venta = ? AND estado = 1')
->order('fecha DESC');
return $this->fetchMany($query, [$venta_id]); return $this->fetchMany($query, [$venta_id]);
} }
public function fetchByVenta(int $venta_id): array
{
$query = $this->connection->getQueryBuilder()
->select()
->from($this->getTable())
->where('venta = ?')
->order('fecha DESC');
return $this->fetchMany($query, [$venta_id]);
}
public function fetchByVentaAndFechaAndTexto(int $venta_id, DateTimeImmutable $fecha, string $texto): Model\Venta\Comentario
{
$query = $this->connection->getQueryBuilder()
->select()
->from($this->getTable())
->where('venta = ? AND fecha = ? AND texto = ?');
return $this->fetchOne($query, [$venta_id, $fecha->format('Y-m-d'), $texto]);
}
} }