Commit 699282d6 authored by Vladimir Trubachoff's avatar Vladimir Trubachoff

Frontend: fixes date format and validation

Backend: added LocalDate (de-)serializer
parent 9aba07ea
package com.example.testj.serializer;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class CustomLocalDateDeserializer extends JsonDeserializer<LocalDate> {
@Override
public LocalDate deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
String dateAsString = jsonParser.getText();
if (dateAsString.isEmpty()) return null;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-M-d");
return LocalDate.parse(dateAsString, formatter);
}
}
\ No newline at end of file
package com.example.testj.serializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class CustomLocalDateSerializer extends JsonSerializer<LocalDate> {
@Override
public void serialize(LocalDate value, JsonGenerator generator, SerializerProvider provider) throws IOException {
if (value == null) {
generator.writeNull();
} else {
generator.writeString(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
}
}
\ No newline at end of file
package com.example.testj.service.dto;
import com.example.testj.serializer.CustomLocalDateDeserializer;
import com.example.testj.serializer.CustomLocalDateSerializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
......@@ -10,7 +14,7 @@ import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
/**
* DTO for {@link com.example.testj.domain.Order}
......@@ -26,11 +30,13 @@ public class OrderDto implements Serializable {
private String client;
@NotNull
@JsonDeserialize(using = CustomLocalDateDeserializer.class)
@JsonSerialize(using = CustomLocalDateSerializer.class)
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private LocalDate date;
@NotBlank
private String address;
private List<OrderLineDto> orderLines;
private Set<OrderLineDto> orderLines;
}
\ No newline at end of file
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { provideHttpClient } from '@angular/common/http';
import {
NgbDateAdapter,
NgbDateParserFormatter,
NgbModule,
} from '@ng-bootstrap/ng-bootstrap';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import {
CustomDateAdapter,
CustomDateParserFormatter,
......
......@@ -9,14 +9,14 @@ import {
*/
@Injectable()
export class CustomDateAdapter {
readonly DELIMITER = '/';
readonly DELIMITER = '-';
fromModel(value: string | null): NgbDateStruct | null {
if (value) {
const date = value.split(this.DELIMITER);
return {
day: parseInt(date[0], 10),
day: parseInt(date[2], 10),
month: parseInt(date[1], 10),
year: parseInt(date[2], 10),
year: parseInt(date[0], 10),
};
}
return null;
......@@ -24,7 +24,11 @@ export class CustomDateAdapter {
toModel(date: NgbDateStruct | null): string | null {
return date
? date.day + this.DELIMITER + date.month + this.DELIMITER + date.year
? date.year +
this.DELIMITER +
('0' + date.month).slice(-2) +
this.DELIMITER +
('0' + date.day).slice(-2)
: null;
}
}
......@@ -34,7 +38,7 @@ export class CustomDateAdapter {
*/
@Injectable()
export class CustomDateParserFormatter extends NgbDateParserFormatter {
readonly DELIMITER = '/';
readonly DELIMITER = '-';
parse(value: string): NgbDateStruct | null {
if (value) {
......@@ -50,7 +54,11 @@ export class CustomDateParserFormatter extends NgbDateParserFormatter {
format(date: NgbDateStruct | null): string {
return date
? date.day + this.DELIMITER + date.month + this.DELIMITER + date.year
? date.day +
this.DELIMITER +
('0' + date.month).slice(-2) +
this.DELIMITER +
date.year
: '';
}
}
import { Goods } from './goods.model';
export interface OrderLine {
id: number;
goods: Goods;
count: number;
}
export interface OrderLineCreateReq {
orderId: number;
goodsId: number;
count: number;
}
export interface OrderLineUpdateReq {
count: number;
}
import { Goods } from './goods.model';
import { OrderLine } from './order-line.model';
export interface Order {
id: number;
......@@ -7,16 +7,3 @@ export interface Order {
date: string;
orderLines: OrderLine[];
}
export interface OrderLine {
id: number;
goods: Goods;
count: number;
}
export interface OrderLineReq {
id?: number;
orderId: number;
goodsId: number;
count: number;
}
......@@ -2,7 +2,10 @@ import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { catchError, EMPTY } from 'rxjs';
import { environment } from '../../../environments/environment';
import { OrderLine, OrderLineReq } from '../model/order.model';
import {
OrderLineCreateReq,
OrderLineUpdateReq,
} from '../model/order-line.model';
@Injectable({
providedIn: 'root',
......@@ -12,14 +15,14 @@ export class OrderLineService {
constructor(private http: HttpClient) {}
put(ol: OrderLineReq) {
const url = `${this.apiUrl}/${ol.id}`;
return this.http.put<OrderLine>(url, ol);
put(id: number, req: OrderLineUpdateReq) {
const url = `${this.apiUrl}/${id}`;
return this.http.put<OrderLineUpdateReq>(url, req);
}
post(ol: OrderLineReq) {
post(req: OrderLineCreateReq) {
const url = this.apiUrl;
return this.http.post<OrderLine>(url, ol);
return this.http.post<OrderLineCreateReq>(url, req);
}
delete(id: number) {
......@@ -28,7 +31,7 @@ export class OrderLineService {
catchError((err: HttpErrorResponse) => {
console.dir(err);
return EMPTY;
})
}),
);
}
}
......@@ -16,7 +16,7 @@ export class AddProductModalComponent extends AbstractBasicComponent {
@Input() goods!: PagedResponseModel<Goods>;
@Input() order!: Order;
@Output() pageNumber = new EventEmitter<number>();
@Output() orderLineChange = new EventEmitter<UpdateCount>();
@Output() countChange = new EventEmitter<UpdateCount>();
modal: NgbModalRef | undefined;
......@@ -32,7 +32,7 @@ export class AddProductModalComponent extends AbstractBasicComponent {
addOrUpdate(goodsId: number, count: number) {
if (count) {
this.orderLineChange.emit({
this.countChange.emit({
goodsId,
count,
});
......
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { OrderLine } from '../../../../core/model/order.model';
import { OrderLine } from '../../../../core/model/order-line.model';
@Component({
selector: 'app-order-line-list',
......@@ -8,9 +8,9 @@ import { OrderLine } from '../../../../core/model/order.model';
})
export class OrderLineListComponent {
@Input() orderLines!: OrderLine[];
@Output() delete = new EventEmitter<number>();
@Output() deleteId = new EventEmitter<number>();
deleteLine(id: number) {
this.delete.emit(id);
this.deleteId.emit(id);
}
}
......@@ -25,7 +25,7 @@
</tr>
<tr>
<th>Date</th>
<td>{{ order.date }}</td>
<td>{{ order.date | date }}</td>
</tr>
</table>
......@@ -34,13 +34,12 @@
class="btn btn-outline-secondary me-2"
(click)="openAddProductModal()"
>
Edit products
Add products
</button>
</div>
<app-order-line-list
(delete)="deleteLine($event)"
(add)="openAddProductModal()"
(deleteId)="deleteLine($event)"
[orderLines]="order.orderLines"
></app-order-line-list>
} @else {
......
......@@ -103,7 +103,7 @@ export class OrderPageComponent
orderModalRef.componentInstance.goods = resp;
});
orderModalRef.componentInstance.orderLineChange
orderModalRef.componentInstance.countChange
.pipe(
takeUntil(this.destroy$),
concatMap((v: UpdateCount) => {
......@@ -111,12 +111,7 @@ export class OrderPageComponent
(ol) => ol.goods.id === v.goodsId,
)?.id;
if (orderLineId) {
return this.orderLineService.put({
id: orderLineId,
orderId: this.order.id,
goodsId: v.goodsId,
count: v.count,
});
return this.orderLineService.put(orderLineId, { count: v.count });
}
return this.orderLineService.post({
orderId: this.order.id,
......
......@@ -34,14 +34,14 @@
</div>
<div class="mb-3">
<label for="dateInput" class="form-label">Date</label>
<div class="input-group">
<div class="input-group has-validation">
<input
class="form-control"
placeholder="dd/mm/yyyy"
placeholder="d-mm-yyyy"
type="text"
ngbDatepicker
#d="ngbDatepicker"
id="addressInput"
id="dateInput"
formControlName="date"
[class.is-invalid]="form.touched && form.get('date')?.invalid"
/>
......@@ -50,7 +50,6 @@
(click)="d.toggle()"
type="button"
></button>
</div>
<div class="invalid-feedback">
<app-form-errors
[control]="form.get('date')!"
......@@ -59,6 +58,7 @@
</div>
</div>
</div>
</div>
<button class="btn btn-outline-primary me-2" (click)="save()">
{{ isNew ? "Create" : "Update" }}
......
......@@ -46,7 +46,7 @@ export class OrderFormComponent {
}
save() {
if (this.form.valid) {
if (this.form.valid && this.form.touched) {
if (this.isNew) {
this.orderService.postOrder({ ...this.form.value }).subscribe({
next: (res) => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment