implement part 2

This commit is contained in:
Sieciech 2021-08-30 16:27:02 +02:00
parent ad5fb576b0
commit 518b697f4a
69 changed files with 37687 additions and 336 deletions

View File

@ -2,3 +2,4 @@ lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%' secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%' public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%' pass_phrase: '%env(JWT_PASSPHRASE)%'
token_ttl: 3600

File diff suppressed because it is too large Load Diff

31971
src/backend/data/states.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ final class Version20210723170329 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
{ {
return ''; return 'create user table';
} }
public function up(Schema $schema): void public function up(Schema $schema): void

View File

@ -14,7 +14,7 @@ final class Version20210723171757 extends AbstractMigration
{ {
public function getDescription(): string public function getDescription(): string
{ {
return ''; return 'update user table';
} }
public function up(Schema $schema): void public function up(Schema $schema): void

View File

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210806124058 extends AbstractMigration
{
public function getDescription(): string
{
return 'create country and country_region tables';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SEQUENCE country_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE country_region_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE country (id INT NOT NULL, code VARCHAR(4) NOT NULL, name VARCHAR(255) NOT NULL, subname VARCHAR(255) DEFAULT NULL, locale_name VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE country_region (id INT NOT NULL, country_id INT NOT NULL, code VARCHAR(4) NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_4F1A1A05F92F3E70 ON country_region (country_id)');
$this->addSql('ALTER TABLE country_region ADD CONSTRAINT FK_4F1A1A05F92F3E70 FOREIGN KEY (country_id) REFERENCES country (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE "user" ADD country_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE "user" ADD state_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE "user" DROP country');
$this->addSql('ALTER TABLE "user" DROP state');
$this->addSql('ALTER TABLE "user" ADD CONSTRAINT FK_8D93D649F92F3E70 FOREIGN KEY (country_id) REFERENCES country (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE "user" ADD CONSTRAINT FK_8D93D6495D83CC1 FOREIGN KEY (state_id) REFERENCES country_region (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX IDX_8D93D649F92F3E70 ON "user" (country_id)');
$this->addSql('CREATE INDEX IDX_8D93D6495D83CC1 ON "user" (state_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('ALTER TABLE country_region DROP CONSTRAINT FK_4F1A1A05F92F3E70');
$this->addSql('ALTER TABLE "user" DROP CONSTRAINT FK_8D93D649F92F3E70');
$this->addSql('ALTER TABLE "user" DROP CONSTRAINT FK_8D93D6495D83CC1');
$this->addSql('DROP SEQUENCE country_id_seq CASCADE');
$this->addSql('DROP SEQUENCE country_region_id_seq CASCADE');
$this->addSql('DROP TABLE country');
$this->addSql('DROP TABLE country_region');
$this->addSql('DROP INDEX IDX_8D93D649F92F3E70');
$this->addSql('DROP INDEX IDX_8D93D6495D83CC1');
$this->addSql('ALTER TABLE "user" ADD country VARCHAR(3) DEFAULT NULL');
$this->addSql('ALTER TABLE "user" ADD state VARCHAR(10) DEFAULT NULL');
$this->addSql('ALTER TABLE "user" DROP country_id');
$this->addSql('ALTER TABLE "user" DROP state_id');
}
}

View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210806124110 extends AbstractMigration
{
public function getDescription(): string
{
return 'import countries';
}
public function up(Schema $schema): void
{
$dataDirectory = dirname(__FILE__, 2).'/data';
$countries = json_decode(file_get_contents($dataDirectory.'/countries.json'));
foreach ($countries as $country) {
$this->addSql('INSERT INTO country (id, name, locale_name, code) VALUES (:id, :name, :localeName, :code)', [
'id' => $country->id,
'name' => $country->name,
'localeName' => $country->localeName,
'code' => $country->code,
]);
}
$states = json_decode(file_get_contents($dataDirectory.'/states.json'));
foreach ($states as $state) {
$this->addSql('INSERT INTO country_region (id, name, code, country_id) VALUES (:id, :name, :code, :country)', [
'id' => $state->id,
'name' => $state->name,
'code' => $state->code,
'country' => $state->countryId,
]);
}
}
public function down(Schema $schema): void
{
$this->addSql('TRUNCATE country');
$this->addSql('TRUNCATE country_region');
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Controller;
use App\Traits\JsonResponseTrait;
use App\Repository\CountryRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class CountryController extends AbstractController
{
use JsonResponseTrait;
public function __construct(private CountryRepository $countryRepository) {
}
#[Route('/api/country', methods: ["GET"])]
public function index()
{
$countries = $this->countryRepository->findAllFlat();
//dd($countries);
return $this->ok($countries);
}
}

View File

@ -2,10 +2,10 @@
namespace App\Entity\Abstraction; namespace App\Entity\Abstraction;
use ReflectionClass;
use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
class BaseEntity { class BaseEntity {
protected array $hidden = []; protected array $hidden = [];
@ -13,9 +13,14 @@ class BaseEntity {
private array $systemParams = ['hidden', 'map', 'systemParams']; private array $systemParams = ['hidden', 'map', 'systemParams'];
public function toArray() { public function toArray() {
$output = []; $output = [];
$normalizers = [new ObjectNormalizer()]; $defaultContext = [
AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object, $format, $context) {
return $object->getName();
},
];
$normalizers = [new ObjectNormalizer(defaultContext: $defaultContext)];
$serializer = new Serializer($normalizers); $serializer = new Serializer($normalizers);
$array = $serializer->normalize($this, null); $array = $serializer->normalize($this, null, [ AbstractObjectNormalizer::ENABLE_MAX_DEPTH => true ]);
$hidden = array_merge($this->hidden, $this->systemParams); $hidden = array_merge($this->hidden, $this->systemParams);
foreach ($array as $key => $value) { foreach ($array as $key => $value) {

View File

@ -0,0 +1,135 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use App\Repository\CountryRepository;
use App\Entity\Abstraction\BaseEntity;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
/**
* @ORM\Entity(repositoryClass=CountryRepository::class)
*/
class Country extends BaseEntity
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=4)
*/
private $code;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @ORM\OneToMany(targetEntity=CountryRegion::class, mappedBy="country")
*/
private $regions;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $subname;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $localeName;
public function __construct()
{
$this->regions = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getCode(): ?string
{
return $this->code;
}
public function setCode(string $code): self
{
$this->code = $code;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
/**
* @return Collection|CountryRegion[]
*/
public function getRegions(): Collection
{
return $this->regions ?? new ArrayCollection();
}
public function addRegion(CountryRegion $region): self
{
if (!$this->regions->contains($region)) {
$this->regions[] = $region;
$region->setCountry($this);
}
return $this;
}
public function removeRegion(CountryRegion $region): self
{
if ($this->regions->removeElement($region)) {
// set the owning side to null (unless already changed)
if ($region->getCountry() === $this) {
$region->setCountry(null);
}
}
return $this;
}
public function getSubname(): ?string
{
return $this->subname;
}
public function setSubname(?string $subname): self
{
$this->subname = $subname;
return $this;
}
public function getLocaleName(): ?string
{
return $this->localeName;
}
public function setLocaleName(?string $localeName): self
{
$this->localeName = $localeName;
return $this;
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use App\Entity\Abstraction\BaseEntity;
use App\Repository\CountryRegionRepository;
/**
* @ORM\Entity(repositoryClass=CountryRegionRepository::class)
*/
class CountryRegion extends BaseEntity
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=4)
*/
private $code;
/**
* @ORM\ManyToOne(targetEntity=Country::class, inversedBy="regions")
* @ORM\JoinColumn(nullable=false)
*/
private $country;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
public function getId(): ?int
{
return $this->id;
}
public function getCode(): ?string
{
return $this->code;
}
public function setCode(string $code): self
{
$this->code = $code;
return $this;
}
public function getCountry(): ?Country
{
return $this->country;
}
public function setCountry(?Country $country): self
{
$this->country = $country;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
}

View File

@ -5,6 +5,7 @@ namespace App\Entity;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use App\Repository\UserRepository; use App\Repository\UserRepository;
use App\Entity\Abstraction\BaseEntity; use App\Entity\Abstraction\BaseEntity;
use App\Enums\UserRoleEnum;
use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Security\User\JWTUserInterface; use Lexik\Bundle\JWTAuthenticationBundle\Security\User\JWTUserInterface;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
@ -56,15 +57,16 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse
private $avatar; private $avatar;
/** /**
* @ORM\Column(type="string", length=3, nullable=true) * @ORM\ManyToOne(targetEntity=Country::class)
*/ */
private $country; private $country;
/** /**
* @ORM\Column(type="string", length=10, nullable=true) * @ORM\ManyToOne(targetEntity=CountryRegion::class)
*/ */
private $state; private $state;
public static function createFromPayload($username, array $payload) public static function createFromPayload($username, array $payload)
{ {
$user = new User(); $user = new User();
@ -108,7 +110,12 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse
{ {
$roles = $this->roles; $roles = $this->roles;
// guarantee every user at least has ROLE_USER // guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER'; $roles[] = UserRoleEnum::User;
if ($this->id === 1) {
$roles[] = UserRoleEnum::UserVerified;
$roles[] = UserRoleEnum::Moderator;
$roles[] = UserRoleEnum::Administrator;
}
return array_unique($roles); return array_unique($roles);
} }
@ -203,33 +210,33 @@ class User extends BaseEntity implements UserInterface, PasswordAuthenticatedUse
return $this; return $this;
} }
public function getCountry(): ?string public function generateAvatar() {
if (!$this->avatar) {
$this->avatar = 'https://www.gravatar.com/avatar/' . md5($this->email) . '?s=514&d=robohash';
}
}
public function getCountry(): ?Country
{ {
return $this->country; return $this->country;
} }
public function setCountry(?string $country): self public function setCountry(?Country $country): self
{ {
$this->country = $country; $this->country = $country;
return $this; return $this;
} }
public function getState(): ?string public function getState(): ?CountryRegion
{ {
return $this->state; return $this->state;
} }
public function setState(?string $state): self public function setState(?CountryRegion $state): self
{ {
$this->state = $state; $this->state = $state;
return $this; return $this;
} }
public function generateAvatar() {
if (!$this->avatar) {
$this->avatar = 'https://www.gravatar.com/avatar/' . md5($this->email) . '?s=514&d=robohash';
}
}
} }

View File

@ -0,0 +1,13 @@
<?php
namespace App\Enums;
class UserRoleEnum {
const None = 'none';
const User = 'user';
const UserVerified = 'user2';
const Doctor = 'doc';
const DoctorVerified = 'doc2';
const Moderator = 'mod';
const Administrator = 'admin';
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Repository;
use App\Entity\CountryRegion;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method CountryRegion|null find($id, $lockMode = null, $lockVersion = null)
* @method CountryRegion|null findOneBy(array $criteria, array $orderBy = null)
* @method CountryRegion[] findAll()
* @method CountryRegion[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class CountryRegionRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, CountryRegion::class);
}
// /**
// * @return CountryRegion[] Returns an array of CountryRegion objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('c')
->andWhere('c.exampleField = :val')
->setParameter('val', $value)
->orderBy('c.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?CountryRegion
{
return $this->createQueryBuilder('c')
->andWhere('c.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}

View File

@ -0,0 +1,60 @@
<?php
namespace App\Repository;
use App\Entity\Country;
use Doctrine\ORM\Query;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
/**
* @method Country|null find($id, $lockMode = null, $lockVersion = null)
* @method Country|null findOneBy(array $criteria, array $orderBy = null)
* @method Country[] findAll()
* @method Country[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class CountryRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Country::class);
}
public function findAllFlat()
{
return $this->createQueryBuilder('c')
->orderBy('c.name', 'ASC')
->getQuery()
->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true)
->getResult()
;
}
// /**
// * @return Country[] Returns an array of Country objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('c')
->andWhere('c.exampleField = :val')
->setParameter('val', $value)
->orderBy('c.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Country
{
return $this->createQueryBuilder('c')
->andWhere('c.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}

View File

@ -3,7 +3,6 @@
namespace App\Traits; namespace App\Traits;
use App\Entity\Abstraction\BaseEntity; use App\Entity\Abstraction\BaseEntity;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
@ -30,6 +29,14 @@ trait JsonResponseTrait {
$data = $data->toArray(); $data = $data->toArray();
} }
if (is_array($data)) {
foreach ($data as $key => $value) {
if ($value instanceof BaseEntity) {
$data[$key] = $value->toArray();
}
}
}
return new JsonResponse($data, $code, $headers); return new JsonResponse($data, $code, $headers);
} }
} }

View File

@ -1,14 +1,17 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { Route, RouterModule } from '@angular/router'; import { Route, RouterModule } from '@angular/router';
import { AuthTabEnum } from './modules/auth/enums/auth-tab.enum';
import { UserRoleEnum } from './modules/auth/enums/user-role.enum';
import { AuthGuard } from './modules/auth/services/auth/auth.guard'; import { AuthGuard } from './modules/auth/services/auth/auth.guard';
import { NotFoundComponent } from './modules/shared/components/not-found/not-found.component'; import { NotFoundComponent } from './modules/shared/components/not-found/not-found.component';
interface AppMenuEntry { export interface AppMenuEntry {
label: string; label: string;
icon: string; icon: string;
path?: string; path?: string;
matchExact?: boolean; matchExact?: boolean;
level?: number; level?: number;
roles: UserRoleEnum[];
} }
interface AppRoute extends Route { interface AppRoute extends Route {
@ -16,10 +19,6 @@ interface AppRoute extends Route {
} }
export const appRoutes: AppRoute[] = [ export const appRoutes: AppRoute[] = [
{
path: 'auth',
loadChildren: () => import('./modules/auth/auth.module').then(m => m.AuthModule),
},
{ {
path: '', path: '',
component: NotFoundComponent, component: NotFoundComponent,
@ -27,12 +26,41 @@ export const appRoutes: AppRoute[] = [
{ {
label: 'MENU.HOME', label: 'MENU.HOME',
icon: 'fa fa-home', icon: 'fa fa-home',
roles: [],
matchExact: true, matchExact: true,
}, },
], ],
canActivate: [ AuthGuard, ], canActivate: [ AuthGuard, ],
canActivateChild: [ AuthGuard, ], canActivateChild: [ AuthGuard, ],
}, },
{
path: 'auth',
loadChildren: () => import('./modules/auth/auth.module').then(m => m.AuthModule),
menuEntries: [
{
path: `auth/${AuthTabEnum.Login}`,
label: 'AUTH.SIGN_IN',
icon: 'fa fa-sign-in',
roles: [ UserRoleEnum.None ],
matchExact: true,
},
{
path: `auth/${AuthTabEnum.Register}`,
label: 'AUTH.SIGN_UP',
icon: 'fa fa-sign-out',
roles: [ UserRoleEnum.None ],
matchExact: true,
},
{
path: `auth/${AuthTabEnum.RestorePassword}`,
label: 'AUTH.RESTORE_ACCOUNT',
icon: 'fa fa-undo',
roles: [ UserRoleEnum.None ],
matchExact: true,
},
],
},
{ {
path: 'profile', path: 'profile',
loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule), loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule),
@ -40,6 +68,7 @@ export const appRoutes: AppRoute[] = [
{ {
label: 'MENU.PROFILE', label: 'MENU.PROFILE',
icon: 'fa fa-user', icon: 'fa fa-user',
roles: [ UserRoleEnum.User ],
}, },
], ],
canActivate: [ AuthGuard, ], canActivate: [ AuthGuard, ],
@ -52,6 +81,7 @@ export const appRoutes: AppRoute[] = [
{ {
label: 'MENU.COMMUNITY', label: 'MENU.COMMUNITY',
icon: 'fa fa-users', icon: 'fa fa-users',
roles: [ UserRoleEnum.User ],
}, },
], ],
canActivate: [ AuthGuard, ], canActivate: [ AuthGuard, ],
@ -64,6 +94,7 @@ export const appRoutes: AppRoute[] = [
{ {
label: 'MENU.QUESTIONS', label: 'MENU.QUESTIONS',
icon: 'fa fa-question', icon: 'fa fa-question',
roles: [ UserRoleEnum.User ],
level: 1, level: 1,
} }
], ],
@ -77,6 +108,7 @@ export const appRoutes: AppRoute[] = [
{ {
label: 'MENU.MESSAGES', label: 'MENU.MESSAGES',
icon: 'fa fa-comments', icon: 'fa fa-comments',
roles: [ UserRoleEnum.User ],
}, },
], ],
canActivate: [ AuthGuard, ], canActivate: [ AuthGuard, ],
@ -89,6 +121,7 @@ export const appRoutes: AppRoute[] = [
{ {
label: 'MENU.TESTS', label: 'MENU.TESTS',
icon: 'fa fa-heartbeat', icon: 'fa fa-heartbeat',
roles: [ UserRoleEnum.User ],
}, },
], ],
canActivate: [ AuthGuard, ], canActivate: [ AuthGuard, ],
@ -101,6 +134,7 @@ export const appRoutes: AppRoute[] = [
{ {
label: 'MENU.RESEARCH', label: 'MENU.RESEARCH',
icon: 'fa fa-flask', icon: 'fa fa-flask',
roles: [ UserRoleEnum.User ],
}, },
], ],
canActivate: [ AuthGuard, ], canActivate: [ AuthGuard, ],
@ -113,12 +147,14 @@ export const appRoutes: AppRoute[] = [
{ {
label: 'MENU.ADMIN', label: 'MENU.ADMIN',
icon: 'fa fa-id-card', icon: 'fa fa-id-card',
roles: [ UserRoleEnum.Administrator, UserRoleEnum.Moderator ],
matchExact: true, matchExact: true,
}, },
{ {
path: 'admin/users', path: 'admin/users',
label: 'MENU.USERS', label: 'MENU.USERS',
icon: 'fa fa-users', icon: 'fa fa-users',
roles: [ UserRoleEnum.Administrator, UserRoleEnum.Moderator ],
level: 1, level: 1,
} }
], ],

View File

@ -1,7 +1,7 @@
<ng-template #toolbar> <ng-template #toolbar>
<mat-toolbar class="toolbar-background"> <mat-toolbar class="toolbar-background">
<button mat-icon-button (click)="toggleSidebar()" *ngIf="!isSidebarHidden"> <button mat-icon-button (click)="toggleSidebar()">
<i class="fa fa-bars"></i> <i class="fa fa-bars"></i>
</button> </button>
<span>{{ 'APP.NAME' | translate }}</span> <span>{{ 'APP.NAME' | translate }}</span>
@ -17,13 +17,15 @@
<ng-container *ngTemplateOutlet="toolbar"></ng-container> <ng-container *ngTemplateOutlet="toolbar"></ng-container>
</ng-container> </ng-container>
<mat-drawer-container class="flex-grow-1"> <mat-drawer-container class="flex-grow-1">
<mat-drawer [mode]="sidebarMode" [opened]="isSidebarOpen" (openedChange)="onSidebarOpenedChange($event)" *ngIf="!isSidebarHidden"> <mat-drawer [mode]="sidebarMode" [opened]="isSidebarOpen" (openedChange)="onSidebarOpenedChange($event)">
<div class="menu"> <div class="menu">
<div> <div>
<ng-container *ngFor="let route of appRoutes"> <ng-container *ngFor="let route of appRoutes">
<ng-container *ngIf="route.menuEntries"> <ng-container *ngIf="route.menuEntries">
<ng-container
*ngFor="let menu of route.menuEntries">
<div <div
*ngFor="let menu of route.menuEntries" *ngIf="canShowMenuEntry(menu)"
class="menu-item" class="menu-item"
[attr.style]="menu.level ? 'margin-left: '+(menu.level * 20)+'px' : ''" [attr.style]="menu.level ? 'margin-left: '+(menu.level * 20)+'px' : ''"
[routerLink]="menu.path ? menu.path : route.path" [routerLink]="menu.path ? menu.path : route.path"
@ -34,6 +36,7 @@
</div> </div>
</ng-container> </ng-container>
</ng-container> </ng-container>
</ng-container>
</div> </div>
<div> <div>
<div class="d-flex user-box" *ngIf="user"> <div class="d-flex user-box" *ngIf="user">
@ -46,21 +49,14 @@
</button> </button>
</div> </div>
<mat-menu #usermenu="matMenu" yPosition="above" xPosition="before" class="w-220"> <mat-menu #usermenu="matMenu" yPosition="above" xPosition="before" class="w-220">
<mat-form-field class="w-100 px-3"> <button mat-menu-item routerLink="/profile">
<mat-label>{{ 'APP.LANGUAGE' | translate }}</mat-label> {{ 'APP.USER_SETTINGS' | translate }}
<mat-select [formControl]="langControl"> </button>
<mat-option *ngFor="let lang of langs" [value]="lang">{{ 'LANGUAGE.'+lang.toUpperCase() | translate }}</mat-option> <button mat-menu-item routerLink="/profile/settings">
</mat-select> {{ 'APP.USER_SITE_SETTINGS' | translate }}
</mat-form-field> </button>
<mat-form-field class="w-100 px-3">
<mat-label>{{ 'APP.THEME' | translate }}</mat-label>
<mat-select [formControl]="themeControl">
<mat-option *ngFor="let theme of themes" [value]="theme">{{ 'THEME.'+theme.toUpperCase() | translate }}</mat-option>
</mat-select>
</mat-form-field>
<button mat-menu-item (click)="logout()"> <button mat-menu-item (click)="logout()">
Wyloguj {{ 'APP.LOGOUT' | translate}}
</button> </button>
</mat-menu> </mat-menu>
</div> </div>
@ -73,7 +69,7 @@
<ng-container *ngTemplateOutlet="toolbar"></ng-container> <ng-container *ngTemplateOutlet="toolbar"></ng-container>
</ng-container> </ng-container>
<div class="example-sidenav-content"> <div class="content">
<router-outlet></router-outlet> <router-outlet></router-outlet>
</div> </div>
</mat-drawer-container> </mat-drawer-container>

View File

@ -89,3 +89,6 @@ $sidebar-width: 250px;
justify-content: center; justify-content: center;
} }
} }
.content{
flex-grow: 1;
}

View File

@ -1,13 +1,12 @@
import { Component } from '@angular/core'; import { AfterContentInit, Component } from '@angular/core';
import { FormControl } from '@angular/forms'; import { AppMenuEntry, appRoutes } from './app-routing.module';
import { appRoutes } from './app-routing.module';
import { AppService, WindowSize } from './modules/shared/services/app/app.service'; import { AppService, WindowSize } from './modules/shared/services/app/app.service';
import { BrowserStorageService } from './modules/shared/services/browser-storage/browser-storage.service'; import { BrowserStorageService } from './modules/shared/services/browser-storage/browser-storage.service';
import { ThemeService } from './modules/shared/services/theme/theme.service';
import { DomSanitizer, SafeStyle } from '@angular/platform-browser'; import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
import { AuthService } from './modules/auth/services/auth/auth.service'; import { AuthService } from './modules/auth/services/auth/auth.service';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { UserModel } from './modules/auth/models/user.model'; import { UserModel } from './modules/auth/models/user.model';
import { UserRoleEnum } from './modules/auth/enums/user-role.enum';
enum SidebarOpenEnum { enum SidebarOpenEnum {
Default, Default,
@ -20,22 +19,19 @@ enum SidebarOpenEnum {
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss']
}) })
export class AppComponent { export class AppComponent implements AfterContentInit {
isMobile = true; isMobile = true;
title = 'CureNet'; title = 'CureNet';
sidebarOpen = SidebarOpenEnum.Default; sidebarOpen = SidebarOpenEnum.Default;
sidebarMode = 'over'; sidebarMode = 'over';
defaultSidebarOpen = false; defaultSidebarOpen = false;
lang: string;
theme: string;
langs: string[] = [];
themes: string[] = [];
themeControl = new FormControl();
langControl = new FormControl();
appRoutes = appRoutes; appRoutes = appRoutes;
user: UserModel; user: UserModel;
isSidebarHidden = false; loaded = false;
//isSidebarHidden = false;
dynamicToolbarComponents = []; dynamicToolbarComponents = [];
roles: UserRoleEnum[] = [ UserRoleEnum.None ];
get isSidebarOpen(): boolean { get isSidebarOpen(): boolean {
switch (this.sidebarOpen) { switch (this.sidebarOpen) {
@ -50,31 +46,51 @@ export class AppComponent {
constructor( constructor(
private appService: AppService, private appService: AppService,
private themeService: ThemeService,
private browserStorageService: BrowserStorageService, private browserStorageService: BrowserStorageService,
private sanitizer: DomSanitizer, private sanitizer: DomSanitizer,
private authService: AuthService, private authService: AuthService,
private router: Router, private router: Router,
) { ) {
this.configureSidebarEvents(); }
this.configureThemeEvents();
this.configureLanguageEvents(); ngAfterContentInit () {
this.configureResizeEvents(); this.configureResizeEvents();
this.configureUserEvents(); this.configureUserEvents();
this.configureSidebarEvents();
}
canShowMenuEntry(menu: AppMenuEntry): boolean {
return !menu.roles.some(i => !this.roles.includes(i));
} }
configureUserEvents(): void { configureUserEvents(): void {
this.user = this.authService.getUser(); this.setUser(this.authService.getUser());
this.authService.userChange.subscribe(user => { this.authService.userChange.subscribe(user => this.setUser(user));
}
setUser(user: UserModel) {
console.log({user, cuser: this.user});
if (!user && !this.user) {
return;
}
if (user && this.user) {
if (user.id === this.user.id && user.roles.join(',') === this.user.roles.join(',')) {
return;
}
}
this.user = user; this.user = user;
}); if (this.user) {
this.roles = this.user.roles;
} else {
this.roles = [ UserRoleEnum.None ];
}
} }
configureSidebarEvents(): void { configureSidebarEvents(): void {
this.isSidebarHidden = this.appService.getSidebarHidden(); //this.isSidebarHidden = this.appService.getSidebarHidden();
this.appService.sidebarHiddenChange.subscribe(hidden => { //this.appService.sidebarHiddenChange.subscribe(hidden => {
this.isSidebarHidden = hidden; // this.isSidebarHidden = hidden;
}); //});
const sidebarUserPrefference = this.browserStorageService.getItem('sidebar.open'); const sidebarUserPrefference = this.browserStorageService.getItem('sidebar.open');
if (sidebarUserPrefference !== null) { if (sidebarUserPrefference !== null) {
this.sidebarOpen = sidebarUserPrefference; this.sidebarOpen = sidebarUserPrefference;
@ -84,32 +100,6 @@ export class AppComponent {
}); });
} }
configureThemeEvents(): void {
this.themes = this.themeService.getThemes();
this.themeControl.valueChanges.subscribe(theme => {
this.themeService.setTheme(theme);
});
this.onThemeChanged(this.themeService.getTheme());
this.themeService.themeChange.subscribe(theme => {
this.onThemeChanged(theme);
});
}
configureLanguageEvents(): void {
this.langs = this.appService.getLangs();
this.lang = this.appService.getLang();
this.appService.changeLang(this.lang);
this.langControl.valueChanges.subscribe(lang => {
this.appService.changeLang(lang);
});
this.onLangChanged(this.appService.getLang());
this.appService.langChange.subscribe(lang => {
this.onLangChanged(lang);
});
}
configureResizeEvents(): void { configureResizeEvents(): void {
this.onResize(this.appService.size); this.onResize(this.appService.size);
this.appService.sizeChange.subscribe(size => { this.appService.sizeChange.subscribe(size => {
@ -117,14 +107,6 @@ export class AppComponent {
}); });
} }
onThemeChanged(theme: string): void {
if (theme === undefined) {
return;
}
this.theme = theme;
this.themeControl.setValue(theme);
}
onResize(size: WindowSize): void { onResize(size: WindowSize): void {
if (size === undefined) { if (size === undefined) {
return; return;
@ -134,14 +116,6 @@ export class AppComponent {
this.sidebarMode = this.isMobile ? 'over' : 'side'; this.sidebarMode = this.isMobile ? 'over' : 'side';
} }
onLangChanged(lang: string): void {
if (lang === undefined) {
return;
}
this.lang = lang;
this.langControl.setValue(lang);
}
toggleSidebar(): void { toggleSidebar(): void {
this.sidebarOpen = this.isSidebarOpen ? SidebarOpenEnum.Closed : SidebarOpenEnum.Open; this.sidebarOpen = this.isSidebarOpen ? SidebarOpenEnum.Closed : SidebarOpenEnum.Open;
this.browserStorageService.setItem('sidebar.open', this.sidebarOpen); this.browserStorageService.setItem('sidebar.open', this.sidebarOpen);

View File

@ -15,6 +15,9 @@ import { TokenInterceptor } from './modules/shared/interceptors/token/token.inte
import { AuthTokenService } from './modules/shared/services/auth/auth-token.service'; import { AuthTokenService } from './modules/shared/services/auth/auth-token.service';
import { AuthService } from './modules/auth/services/auth/auth.service'; import { AuthService } from './modules/auth/services/auth/auth.service';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { ErrorHandlerInterceptor } from './modules/shared/interceptors/error-handler/error-handler.interceptor';
import { NotificationService } from './modules/shared/notification/notification.service';
import { MatSnackBar } from '@angular/material/snack-bar';
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader { export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
return new TranslateHttpLoader(http, '/assets/lang/', '.json'); return new TranslateHttpLoader(http, '/assets/lang/', '.json');
@ -48,8 +51,14 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
BrowserStorageService, BrowserStorageService,
AuthTokenService, AuthTokenService,
AuthService, AuthService,
{ provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true } NotificationService,
MatSnackBar,
{ provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: ErrorHandlerInterceptor, multi: true },
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { } export class AppModule {
constructor(public themeService: ThemeService) {
}
}

View File

@ -16,7 +16,6 @@ const routes: Route[] = [
path: AuthTabEnum.RestorePassword, path: AuthTabEnum.RestorePassword,
component: AuthComponent, component: AuthComponent,
}, },
{ {
path: '**', path: '**',
redirectTo: 'login', redirectTo: 'login',

View File

@ -17,7 +17,7 @@
</mat-form-field> </mat-form-field>
<div class="text-end"> <div class="text-end">
<button mat-button (click)="selectedIndexChange(getSelectedIndex(AuthTabEnum.RestorePassword))">{{ 'AUTH.RESTORE_ACCOUNT' | translate }}</button> <button mat-button (click)="selectedIndexChange(getSelectedIndex(AuthTabEnum.RestorePassword))">{{ 'AUTH.RESTORE_ACCOUNT' | translate }}</button>
<button mat-flat-button color="primary" (click)="login()">{{ 'AUTH.SIGN_IN' | translate }}</button> <button mat-flat-button color="primary" (click)="login()" [attr.is-working]="isWorking || null" [disabled]="isWorking">{{ 'AUTH.SIGN_IN' | translate }}</button>
</div> </div>
</div> </div>
</mat-tab> </mat-tab>
@ -44,7 +44,7 @@
<input formControlName="password" type="password" matInput> <input formControlName="password" type="password" matInput>
</mat-form-field> </mat-form-field>
<div class="text-end"> <div class="text-end">
<button mat-flat-button color="primary" (click)="register()">{{ 'AUTH.SIGN_UP' | translate }}</button> <button mat-flat-button color="primary" (click)="register()" [attr.is-working]="isWorking || null" [disabled]="isWorking">{{ 'AUTH.SIGN_UP' | translate }}</button>
</div> </div>
</div> </div>
</mat-tab> </mat-tab>
@ -57,7 +57,7 @@
</mat-form-field> </mat-form-field>
<div class="text-end"> <div class="text-end">
<button mat-button (click)="selectedIndexChange(getSelectedIndex(AuthTabEnum.Login))">{{ 'AUTH.CANCEL' | translate }}</button> <button mat-button (click)="selectedIndexChange(getSelectedIndex(AuthTabEnum.Login))">{{ 'AUTH.CANCEL' | translate }}</button>
<button mat-flat-button color="primary">{{ 'AUTH.SEND_NEW_PASSWORD' | translate }}</button> <button mat-flat-button color="primary" [attr.is-working]="isWorking || null" [disabled]="isWorking">{{ 'AUTH.SEND_NEW_PASSWORD' | translate }}</button>
</div> </div>
</div> </div>
</mat-tab> </mat-tab>

View File

@ -30,6 +30,7 @@ export class AuthComponent implements OnInit, OnDestroy {
]; ];
showRestore = false; showRestore = false;
AuthTabEnum = AuthTabEnum; AuthTabEnum = AuthTabEnum;
isWorking = false;
constructor( constructor(
private appService: AppService, private appService: AppService,
@ -91,7 +92,9 @@ export class AuthComponent implements OnInit, OnDestroy {
ngOnInit(): void { ngOnInit(): void {
this.appService.setSidebarHidden(true); this.appService.setSidebarHidden(true);
setTimeout(() => {
this.appService.addDynamicToolbarComponent(ThemeSwitcherComponent); this.appService.addDynamicToolbarComponent(ThemeSwitcherComponent);
}, 50);
} }
ngOnDestroy(): void { ngOnDestroy(): void {
@ -100,19 +103,25 @@ export class AuthComponent implements OnInit, OnDestroy {
} }
register(): void { register(): void {
this.isWorking = true;
this.authService.createAccount(this.registerForm.getRawValue()).subscribe(data => { this.authService.createAccount(this.registerForm.getRawValue()).subscribe(data => {
this.loginForm.patchValue({ this.loginForm.patchValue({
email: this.registerForm.controls.email.value, email: this.registerForm.controls.email.value,
password: this.registerForm.controls.password.value, password: this.registerForm.controls.password.value,
}); });
this.selectedIndexChange(this.getSelectedIndex(AuthTabEnum.Login)); this.selectedIndexChange(this.getSelectedIndex(AuthTabEnum.Login));
}).add(() => {
this.isWorking = false;
}); });
} }
login(): void { login(): void {
this.authService.login(this.loginForm.getRawValue()).subscribe(data => { this.isWorking = true;
this.authService.login(this.loginForm.getRawValue()).subscribe(() => {
const afterUrl = '/'; const afterUrl = '/';
this.router.navigateByUrl(afterUrl); this.router.navigateByUrl(afterUrl);
}).add(() => {
this.isWorking = false;
}); });
} }
} }

View File

@ -0,0 +1,9 @@
export enum UserRoleEnum {
None = 'none',
User = 'user',
UserVerified = 'user2',
Doctor = 'doc',
DoctorVerified = 'doc2',
Moderator = 'mod',
Administrator = 'admin',
}

View File

@ -1,8 +1,11 @@
import { UserRoleEnum } from "../enums/user-role.enum";
export interface UserModel { export interface UserModel {
id: number; id: number;
name: string; name: string;
surname: string; surname: string;
avatar: string | null; avatar: string | null;
country: string | null; country: number | null;
state: string | null; state: string | null;
roles: UserRoleEnum[];
} }

View File

@ -30,8 +30,10 @@ export class AuthService {
return this.user; return this.user;
} }
checkUser(): void { checkUser(): Promise<UserModel> {
return new Promise<UserModel>((resolve) => {
this.http.post<UserModel>('/api/user-check', {}).subscribe(user => { this.http.post<UserModel>('/api/user-check', {}).subscribe(user => {
console.log({user});
this.userChange.next(user); this.userChange.next(user);
if (AuthService.updateAgent) { if (AuthService.updateAgent) {
clearTimeout(AuthService.updateAgent); clearTimeout(AuthService.updateAgent);
@ -39,9 +41,11 @@ export class AuthService {
AuthService.updateAgent = setTimeout(() => { AuthService.updateAgent = setTimeout(() => {
this.checkUser(); this.checkUser();
}, 2000) as any; }, 2000) as any;
resolve(user);
}, () => { }, () => {
this.logout(); this.logout();
}); });
});
} }
createAccount(data: RegisterModel): Observable<UserModel> { createAccount(data: RegisterModel): Observable<UserModel> {
@ -55,13 +59,21 @@ export class AuthService {
password: data.password, password: data.password,
}).subscribe(response => { }).subscribe(response => {
this.authTokenService.setToken(response.token); this.authTokenService.setToken(response.token);
this.checkUser(); this.checkUser().then(() => {
out.next(response); out.next(response);
}, () => {
out.next(null);
}).catch(() => {
out.next(null);
});
}); });
return out; return out;
} }
logout(): void { logout(): void {
if (AuthService.updateAgent) {
clearTimeout(AuthService.updateAgent);
}
this.authTokenService.removeToken(); this.authTokenService.removeToken();
this.userChange.next(null); this.userChange.next(null);
this.router.navigate(['/auth']); this.router.navigate(['/auth']);

View File

@ -8,6 +8,8 @@ import {MatMenuModule} from '@angular/material/menu';
import {MatCardModule} from '@angular/material/card'; import {MatCardModule} from '@angular/material/card';
import {MatTabsModule} from '@angular/material/tabs'; import {MatTabsModule} from '@angular/material/tabs';
import {MatInputModule} from '@angular/material/input'; import {MatInputModule} from '@angular/material/input';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatAutocompleteModule} from '@angular/material/autocomplete';
const itemsToExport = [ const itemsToExport = [
MatToolbarModule, MatToolbarModule,
@ -18,6 +20,8 @@ const itemsToExport = [
MatCardModule, MatCardModule,
MatTabsModule, MatTabsModule,
MatInputModule, MatInputModule,
MatFormFieldModule,
MatAutocompleteModule,
]; ];
@NgModule({ @NgModule({

View File

@ -1,15 +0,0 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-profile-edit-avatar',
templateUrl: './profile-edit-avatar.component.html',
styleUrls: ['./profile-edit-avatar.component.scss']
})
export class ProfileEditAvatarComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -1 +1,109 @@
<p>profile-edit-basics works!</p> <div class="full-height-form">
<div class="form-content position-relative">
<div class="scrollable-content" (scroll)="scroll($event)">
<div [style.height.px]="placeholderBoxHeight"></div>
<div class="container" [formGroup]="form">
<div class="form-group">
<h5>{{ 'PROFILE.BASICS' | translate }}</h5>
<div class="form-row">
<div class="form-label width-200">{{ 'AUTH.NAME' | translate }}</div>
<div>
<mat-form-field class="w-100">
<input matInput formControlName="name">
</mat-form-field>
</div>
</div>
<div class="form-row">
<div class="form-label width-200">{{ 'AUTH.SURNAME' | translate }}</div>
<div>
<mat-form-field class="w-100">
<input matInput formControlName="surname">
</mat-form-field>
</div>
</div>
</div>
<h5>{{ 'PROFILE.CONTACT' | translate }}</h5>
<div class="form-group">
<div class="form-row">
<div class="form-label width-200">{{ 'PROFILE.CONTACTS.COUNTRY' | translate }}</div>
<div>
<mat-form-field class="w-100">
<input type="text"
matInput
formControlName="country"
(keyup)="countryFieldChanged($event)"
[matAutocomplete]="autocompleteCountry">
<mat-autocomplete autoActiveFirstOption #autocompleteCountry="matAutocomplete" [displayWith]="displayCountry">
<mat-option *ngFor="let country of filteredCountries | async" [value]="country.id">
{{ country.name }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
</div>
<div class="form-row">
<div class="form-label width-200">{{ 'PROFILE.CONTACTS.STATE' | translate }}</div>
<div>
<mat-form-field class="w-100">
<input matInput formControlName="state">
</mat-form-field>
</div>
</div>
<div class="form-row">
<div class="form-label width-200">{{ 'PROFILE.CONTACTS.CITY' | translate }}</div>
<div>
<mat-form-field class="w-100">
<input matInput formControlName="city">
</mat-form-field>
</div>
</div>
<div class="form-row">
<div class="form-label width-200">{{ 'PROFILE.CONTACTS.ZIP' | translate }}</div>
<div>
<mat-form-field class="w-100">
<input matInput formControlName="zip">
</mat-form-field>
</div>
</div>
<div class="form-row">
<div class="form-label width-200">{{ 'PROFILE.CONTACTS.PHONES' | translate }}</div>
<div>
phones
</div>
</div>
<div class="form-row">
<div class="form-label width-200">{{ 'PROFILE.CONTACTS.EMAILS' | translate }}</div>
<div>
emails
</div>
</div>
</div>
<h5 class="pt-4">{{ 'PROFILE.AVATAR' | translate }}</h5>
<div class="form-group">
<div class="form-row">
<div class="form-label width-200">{{ 'PROFILE.AVATAR' | translate }}</div>
<div>
avatar
</div>
</div>
</div>
</div>
</div>
</div>
<div class="form-footer">
<button mat-flat-button color="primary">zapisz</button>
</div>
</div>

View File

@ -1,5 +1,36 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@ng-stack/forms';
import { Observable, Subject } from 'rxjs';
import { CountryModel } from 'src/app/modules/shared/models/country.model';
import { CountryService } from 'src/app/modules/shared/services/country/country.service';
import { map, startWith } from 'rxjs/operators';
import { AuthService } from 'src/app/modules/auth/services/auth/auth.service';
interface PhoneEntry{
number: string;
name: string;
description: string;
icon: string;
}
interface EmailEntry{
number: string;
name: string;
description: string;
icon: string;
}
class ProfileInformationBasicModel {
name: string;
surname: string;
country: number;
state: string;
city: string;
zip: string;
phones: PhoneEntry[];
emails: EmailEntry[];
}
@Component({ @Component({
selector: 'app-profile-edit-basics', selector: 'app-profile-edit-basics',
templateUrl: './profile-edit-basics.component.html', templateUrl: './profile-edit-basics.component.html',
@ -7,9 +38,72 @@ import { Component, OnInit } from '@angular/core';
}) })
export class ProfileEditBasicsComponent implements OnInit { export class ProfileEditBasicsComponent implements OnInit {
constructor() { } form: FormGroup<ProfileInformationBasicModel>;
onContentScroll = new Subject<number>();
headerHeight = 200;
placeholderBoxHeight = 0;
filteredCountries: Observable<CountryModel[]>;
countryInputChnage = new Subject<string>();
countries: CountryModel[] = [];
countryInput = '';
constructor(
private countryService: CountryService,
authService: AuthService,
formBuilder: FormBuilder,
) {
const phones = formBuilder.array<PhoneEntry>([]);
const emails = formBuilder.array<EmailEntry>([]);
const user = authService.getUser();
this.form = formBuilder.group<ProfileInformationBasicModel>({
name: user.name,
surname: user.surname,
country: user.country,
state: 'state',
city: 'city',
zip: 'zip',
phones,
emails,
});
window['form'] = this.form;
this.countryService.getCountries().subscribe(countries => {
this.countries = countries;
this.countryInputChnage.next(this.countryInput);
this.form.patchValue({
country: this.form.value.country,
});
});
this.filteredCountries = this.countryInputChnage.pipe(
startWith(''),
map(name => name ? this.filterCountries(name) : this.countries.slice())
);
}
displayCountry = (countryId: number) => {
const country = this.countries.find(i => i.id === countryId);
return country ? country.name : '';
}
ngOnInit(): void { ngOnInit(): void {
} }
scroll(e) {
const scrollTop = e.target?.scrollTop;
if (Number(scrollTop) === scrollTop) {
this.placeholderBoxHeight = Math.min(scrollTop, this.headerHeight);
this.onContentScroll.next(scrollTop);
}
}
filterCountries(name: string) {
return this.countries.filter(i => i.name.toLowerCase().includes(name));
}
countryFieldChanged(event) {
this.countryInput = event.target.value.toLowerCase();
this.countryInputChnage.next(this.countryInput);
}
} }

View File

@ -1,15 +0,0 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-profile-edit-contact',
templateUrl: './profile-edit-contact.component.html',
styleUrls: ['./profile-edit-contact.component.scss']
})
export class ProfileEditContactComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1 @@
<p>profile-edit-health works!</p>

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-profile-edit-health',
templateUrl: './profile-edit-health.component.html',
styleUrls: ['./profile-edit-health.component.scss']
})
export class ProfileEditHealthComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1 @@
<p>profile-edit-roles works!</p>

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-profile-edit-roles',
templateUrl: './profile-edit-roles.component.html',
styleUrls: ['./profile-edit-roles.component.scss']
})
export class ProfileEditRolesComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -1 +1,27 @@
<p>profile-edit-settings works!</p> <div class="container">
<div class="form-group">
<div class="form-row">
<div class="form-label">{{ 'APP.LANGUAGE' | translate }}</div>
<div class="width-200">
<mat-form-field class="w-100 px-3">
<mat-select [formControl]="langControl">
<mat-option *ngFor="let lang of langs" [value]="lang">{{ 'LANGUAGE.'+lang.toUpperCase() | translate }}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<div class="form-row">
<div class="form-label">{{ 'APP.THEME' | translate }}</div>
<div class="width-200">
<mat-form-field class="w-100 px-3">
<mat-select [formControl]="themeControl">
<mat-option *ngFor="let theme of themes" [value]="theme.name">{{ 'THEME.'+theme.name.toUpperCase() | translate }}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</div>
</div>

View File

@ -1,4 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { AppService } from 'src/app/modules/shared/services/app/app.service';
import { ThemeDefinition, ThemeService } from 'src/app/modules/shared/services/theme/theme.service';
@Component({ @Component({
selector: 'app-profile-edit-settings', selector: 'app-profile-edit-settings',
@ -6,10 +9,62 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./profile-edit-settings.component.scss'] styleUrls: ['./profile-edit-settings.component.scss']
}) })
export class ProfileEditSettingsComponent implements OnInit { export class ProfileEditSettingsComponent implements OnInit {
themeControl = new FormControl();
langControl = new FormControl();
lang: string;
theme: string;
langs: string[] = [];
themes: ThemeDefinition[] = [];
constructor() { } constructor(
private themeService: ThemeService,
private appService: AppService,
) {
this.configureThemeEvents();
this.configureLanguageEvents();
}
ngOnInit(): void { ngOnInit(): void {
} }
configureLanguageEvents(): void {
this.langs = this.appService.getLangs();
this.lang = this.appService.getLang();
this.appService.changeLang(this.lang);
this.langControl.valueChanges.subscribe(lang => {
this.appService.changeLang(lang);
});
this.onLangChanged(this.appService.getLang());
this.appService.langChange.subscribe(lang => {
this.onLangChanged(lang);
});
}
configureThemeEvents(): void {
this.themes = this.themeService.getThemes();
this.themeControl.valueChanges.subscribe(theme => {
this.themeService.setTheme(theme);
});
this.onThemeChanged(this.themeService.getTheme());
this.themeService.themeChange.subscribe(theme => {
this.onThemeChanged(theme);
});
}
onThemeChanged(theme: string): void {
if (theme === undefined) {
return;
}
this.theme = theme;
this.themeControl.setValue(theme);
}
onLangChanged(lang: string): void {
if (lang === undefined) {
return;
}
this.lang = lang;
this.langControl.setValue(lang);
}
} }

View File

@ -1,5 +1,9 @@
<div class="toolbar-background user-cover"></div> <div>
<div class="user-header-container p-4"> <div class="toolbar-background user-cover"></div>
<div class="user-header-container">
<div class="scrollable-header" [style.--scrolled]="scrolled">
<div #headerContent>
<div class="p-4" >
<mat-card *ngIf="user === null" class="loading-card"> <mat-card *ngIf="user === null" class="loading-card">
loading loading
</mat-card> </mat-card>
@ -13,9 +17,12 @@
</div> </div>
</div> </div>
</mat-card> </mat-card>
</div> </div>
<ng-container *ngIf="user !== null"> </div>
<div class="p-3 d-none d-md-block"> </div>
</div>
<div *ngIf="user !== null" class="main-background">
<div class="p-3 d-block d-md-none">
<h6>{{ currentTabName | translate }}</h6> <h6>{{ currentTabName | translate }}</h6>
</div> </div>
<div class="tab-container"> <div class="tab-container">
@ -30,7 +37,10 @@
</ng-container> </ng-container>
</mat-tab-group> </mat-tab-group>
</div> </div>
<div class="p-3">
<router-outlet></router-outlet>
</div> </div>
</ng-container> </div>
<div class="flex-grow-1 main-background" *ngIf="user !== null">
<div class="h-100">
<router-outlet (activate)="activated($event)" (deactivate)="deactivated($event)"></router-outlet>
</div>
</div>

View File

@ -1,6 +1,20 @@
:host{
height: 100%;
display: flex;
flex-direction: column;
}
.scrollable-header{
overflow: hidden;
> * {
margin-top: calc(var(--scrolled) * -1px);
margin-bottom: calc(var(--scrolled) * -1px);
}
}
.user-cover{ .user-cover{
height: 100px; height: 100px;
background-color: var(--toolbar-background); background-color: var(--toolbar-background);
position: relative;
z-index: -1;
} }
.user-header-container{ .user-header-container{
margin-top: -100px; margin-top: -100px;
@ -26,3 +40,6 @@
.loading-card{ .loading-card{
margin-top: 50px; margin-top: 50px;
} }
.main-background{
background: var(--main-background);
}

View File

@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { DomSanitizer, SafeStyle } from '@angular/platform-browser'; import { DomSanitizer, SafeStyle } from '@angular/platform-browser';
import { ActivatedRoute, ActivatedRouteSnapshot, ActivationStart, Data, Router, RoutesRecognized } from '@angular/router'; import { ActivatedRoute, ActivatedRouteSnapshot, ActivationStart, Data, Router, RoutesRecognized } from '@angular/router';
import { Subscription } from 'rxjs';
import { UserModel } from 'src/app/modules/auth/models/user.model'; import { UserModel } from 'src/app/modules/auth/models/user.model';
import { AuthService } from 'src/app/modules/auth/services/auth/auth.service'; import { AuthService } from 'src/app/modules/auth/services/auth/auth.service';
import { ProfileTabEnum } from '../../enums/profile-tab.enum'; import { ProfileTabEnum } from '../../enums/profile-tab.enum';
@ -20,11 +21,15 @@ interface ProfileTab {
}) })
export class ProfileEditComponent implements OnInit { export class ProfileEditComponent implements OnInit {
scrollSubscriptions: Subscription[] = [];
scrolled = 0;
profileTabRoutes = profileTabRoutes; profileTabRoutes = profileTabRoutes;
currentTabName: string; currentTabName: string;
user: UserModel | null = null; user: UserModel | null = null;
selectedIndex = 0; selectedIndex = 0;
defaultProfileTab = ProfileTabEnum.Basics; defaultProfileTab = ProfileTabEnum.Basics;
loaded = false;
@ViewChild('headerContent') headerContent: ElementRef;
tabs: ProfileTab[] = [ tabs: ProfileTab[] = [
{ {
tab: ProfileTabEnum.Basics, tab: ProfileTabEnum.Basics,
@ -32,20 +37,20 @@ export class ProfileEditComponent implements OnInit {
icon: 'fa fa-id-badge', icon: 'fa fa-id-badge',
}, },
{ {
tab: ProfileTabEnum.Contact, tab: ProfileTabEnum.Health,
label: 'PROFILE.CONTACT', label: 'PROFILE.HEALTH',
icon: 'fa fa-address-book' icon: 'fa fa-heartbeat',
},
{
tab: ProfileTabEnum.Roles,
label: 'PROFILE.ROLES',
icon: 'fa fa-user',
}, },
{ {
tab: ProfileTabEnum.Credentials, tab: ProfileTabEnum.Credentials,
label: 'PROFILE.PASSWORD', label: 'PROFILE.PASSWORD',
icon: 'fa fa-unlock-alt', icon: 'fa fa-unlock-alt',
}, },
{
tab: ProfileTabEnum.Avatar,
label: 'PROFILE.AVATAR',
icon: 'fa fa-picture-o',
},
{ {
tab: ProfileTabEnum.Settings, tab: ProfileTabEnum.Settings,
label: 'PROFILE.SITE_SETTINGS', label: 'PROFILE.SITE_SETTINGS',
@ -71,6 +76,29 @@ export class ProfileEditComponent implements OnInit {
}); });
} }
ngOnInit(): void {
}
activated(component) {
if (component.onContentScroll) {
component.headerHeight = this.headerContent.nativeElement.scrollHeight;
setTimeout(() => {
component.headerHeight = this.headerContent.nativeElement.scrollHeight;
}, 500);
this.scrollSubscriptions.push(
component.onContentScroll.subscribe(position => {
this.scrolled = position / 2;
})
);
}
}
deactivated(component) {
this.scrolled = 0;
this.scrollSubscriptions.forEach(i => i.unsubscribe());
this.scrollSubscriptions = [];
}
onRouteChange(data: Data): void { onRouteChange(data: Data): void {
this.currentTabName = undefined; this.currentTabName = undefined;
if (data?.tab) { if (data?.tab) {
@ -105,9 +133,6 @@ export class ProfileEditComponent implements OnInit {
} }
} }
ngOnInit(): void {
}
url(url: string): SafeStyle { url(url: string): SafeStyle {
return this.sanitizer.bypassSecurityTrustStyle(`url('${url}')`); return this.sanitizer.bypassSecurityTrustStyle(`url('${url}')`);
} }

View File

@ -1,4 +1,6 @@
export enum ProfileTabEnum { export enum ProfileTabEnum {
Health,
Roles,
Basics, Basics,
Contact, Contact,
Credentials, Credentials,

View File

@ -1,14 +1,27 @@
import { Route } from '@angular/router'; import { Route } from '@angular/router';
import { NotFoundComponent } from '../shared/components/not-found/not-found.component';
import { ProfileEditAvatarComponent } from './components/profile-edit-avatar/profile-edit-avatar.component';
import { ProfileEditBasicsComponent } from './components/profile-edit-basics/profile-edit-basics.component'; import { ProfileEditBasicsComponent } from './components/profile-edit-basics/profile-edit-basics.component';
import { ProfileEditContactComponent } from './components/profile-edit-contact/profile-edit-contact.component';
import { ProfileEditCredentialsComponent } from './components/profile-edit-credentials/profile-edit-credentials.component'; import { ProfileEditCredentialsComponent } from './components/profile-edit-credentials/profile-edit-credentials.component';
import { ProfileEditHealthComponent } from './components/profile-edit-health/profile-edit-health.component';
import { ProfileEditRolesComponent } from './components/profile-edit-roles/profile-edit-roles.component';
import { ProfileEditSettingsComponent } from './components/profile-edit-settings/profile-edit-settings.component'; import { ProfileEditSettingsComponent } from './components/profile-edit-settings/profile-edit-settings.component';
import { ProfileEditComponent } from './components/profile-edit/profile-edit.component'; import { ProfileEditComponent } from './components/profile-edit/profile-edit.component';
import { ProfileTabEnum } from './enums/profile-tab.enum'; import { ProfileTabEnum } from './enums/profile-tab.enum';
export const profileTabRoutes: Route[] = [ export const profileTabRoutes: Route[] = [
{
path: 'health',
component: ProfileEditHealthComponent,
data: {
tab: ProfileTabEnum.Health,
},
},
{
path: 'roles',
component: ProfileEditRolesComponent,
data: {
tab: ProfileTabEnum.Roles,
},
},
{ {
path: 'basics', path: 'basics',
component: ProfileEditBasicsComponent, component: ProfileEditBasicsComponent,
@ -16,13 +29,6 @@ export const profileTabRoutes: Route[] = [
tab: ProfileTabEnum.Basics, tab: ProfileTabEnum.Basics,
}, },
}, },
{
path: 'contact',
component: ProfileEditContactComponent,
data: {
tab: ProfileTabEnum.Contact,
},
},
{ {
path: 'credentials', path: 'credentials',
component: ProfileEditCredentialsComponent, component: ProfileEditCredentialsComponent,
@ -30,13 +36,6 @@ export const profileTabRoutes: Route[] = [
tab: ProfileTabEnum.Credentials, tab: ProfileTabEnum.Credentials,
}, },
}, },
{
path: 'avatar',
component: ProfileEditAvatarComponent,
data: {
tab: ProfileTabEnum.Avatar,
},
},
{ {
path: 'settings', path: 'settings',
component: ProfileEditSettingsComponent, component: ProfileEditSettingsComponent,

View File

@ -8,23 +8,29 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { HttpLoaderFactory } from 'src/app/app.module'; import { HttpLoaderFactory } from 'src/app/app.module';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { ProfileEditBasicsComponent } from './components/profile-edit-basics/profile-edit-basics.component'; import { ProfileEditBasicsComponent } from './components/profile-edit-basics/profile-edit-basics.component';
import { ProfileEditContactComponent } from './components/profile-edit-contact/profile-edit-contact.component';
import { ProfileEditCredentialsComponent } from './components/profile-edit-credentials/profile-edit-credentials.component'; import { ProfileEditCredentialsComponent } from './components/profile-edit-credentials/profile-edit-credentials.component';
import { ProfileEditAvatarComponent } from './components/profile-edit-avatar/profile-edit-avatar.component';
import { ProfileEditSettingsComponent } from './components/profile-edit-settings/profile-edit-settings.component'; import { ProfileEditSettingsComponent } from './components/profile-edit-settings/profile-edit-settings.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NgStackFormsModule } from '@ng-stack/forms';
import { ProfileEditHealthComponent } from './components/profile-edit-health/profile-edit-health.component';
import { ProfileEditRolesComponent } from './components/profile-edit-roles/profile-edit-roles.component';
import { CountryService } from '../shared/services/country/country.service';
@NgModule({ @NgModule({
declarations: [ declarations: [
ProfileEditComponent, ProfileEditComponent,
ProfileEditBasicsComponent, ProfileEditBasicsComponent,
ProfileEditContactComponent,
ProfileEditCredentialsComponent, ProfileEditCredentialsComponent,
ProfileEditAvatarComponent,
ProfileEditSettingsComponent, ProfileEditSettingsComponent,
ProfileEditHealthComponent,
ProfileEditRolesComponent,
], ],
imports: [ imports: [
CommonModule, CommonModule,
ProfileRoutingModule, ProfileRoutingModule,
FormsModule,
ReactiveFormsModule,
NgStackFormsModule,
MaterialModule, MaterialModule,
TranslateModule.forChild({ TranslateModule.forChild({
defaultLanguage: 'en', defaultLanguage: 'en',
@ -37,6 +43,7 @@ import { ProfileEditSettingsComponent } from './components/profile-edit-settings
], ],
providers: [ providers: [
AuthService, AuthService,
CountryService,
], ],
}) })
export class ProfileModule { } export class ProfileModule { }

View File

@ -0,0 +1,53 @@
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Injectable, Injector } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { NotificationService } from '../../notification/notification.service';
@Injectable()
export class ErrorHandlerInterceptor implements HttpInterceptor {
get notificationService() {
return this.injector.get(NotificationService);
}
constructor(
private injector: Injector,
) {
}
intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(httpRequest).pipe(
catchError(response => {
switch(response.status) {
case 406:
if (response.error instanceof Blob && response.error.type === 'application/json') {
const result = new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e: Event) => {
resolve(JSON.parse((e.target as any).result));
};
reader.readAsText(response.error);
});
result.then((data) => {
response.error = data;
this.displayNotificationIfValidationError(response);
});
break;
} else {
this.displayNotificationIfValidationError(response);
break;
}
}
return throwError(response);
})
)
}
displayNotificationIfValidationError(response) {
console.log({response});
if (response?.error?.data) {
this.notificationService.error(response.error.data);
}
}
}

View File

@ -0,0 +1,6 @@
export interface CountryRegion {
id: number;
name: string;
code: string;
countryId: number;
}

View File

@ -0,0 +1,5 @@
export interface CountryModel {
id: number;
name: string;
code: string;
}

View File

@ -1,9 +1,9 @@
export class User { export class UserModel {
id: number; id: number;
email: string; email: string;
name: string; name: string;
surname: string; surname: string;
avatar: string; avatar: string;
country: string; country: number;
state: string; state: string;
} }

View File

@ -0,0 +1,46 @@
import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
enum NotificationType {
Success,
Error,
Info,
}
@Injectable()
export class NotificationService {
constructor(private snackBar: MatSnackBar) { }
notify(type: NotificationType, title: string) {
let action: string;
let panelClass: string;
let duration = 1500000;
switch (type) {
case NotificationType.Success:
action = 'OK';
panelClass = 'notify-success';
break;
case NotificationType.Error:
action = 'OK';
panelClass = 'notify-error';
break;
}
this.snackBar.open(title, action, {
panelClass,
duration,
});
}
success(title: string) {
return this.notify(NotificationType.Success, title);
}
error(title: string) {
return this.notify(NotificationType.Error, title);
}
}

View File

@ -0,0 +1,16 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { CountryModel } from '../../models/country.model';
@Injectable()
export class CountryService {
constructor(private http: HttpClient) {
}
getCountries(): Observable<CountryModel[]> {
return this.http.get<CountryModel[]>('/api/country');
}
}

View File

@ -2,6 +2,12 @@ import { Injectable } from '@angular/core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { BrowserStorageService } from '../browser-storage/browser-storage.service'; import { BrowserStorageService } from '../browser-storage/browser-storage.service';
export class ThemeDefinition {
name: string;
isDark: boolean;
isDefault: boolean;
relatedTheme: string | undefined;
}
@Injectable() @Injectable()
export class ThemeService { export class ThemeService {
private theme: string; private theme: string;
@ -32,10 +38,20 @@ export class ThemeService {
} }
} }
getThemes(): string[] { getThemes(): ThemeDefinition[] {
return [ return [
'light', {
'dark', name: 'light',
isDark: false,
isDefault: true,
relatedTheme: 'dark',
},
{
name: 'dark',
isDark: true,
isDefault: true,
relatedTheme: 'light',
}
]; ];
} }
} }

View File

@ -5,12 +5,18 @@ $toolbar-background: map.get($theme, color, background, app-bar);
$toolbar-color: map.get($theme, color, primary, contrast, 500) !default; $toolbar-color: map.get($theme, color, primary, contrast, 500) !default;
$main-background: map.get($theme, color, background, background) !default; $main-background: map.get($theme, color, background, background) !default;
$warn-color: map.get($theme, warn, 500) !default; $warn-color: map.get($theme, warn, 500) !default;
$success-color: map.get($theme, success, 500) !default;
$divider-color: map.get($theme, foreground, divider) !default;
$dialog-background: map.get($theme, background, dialog) !default;
body { body {
--primary-color: #{$primary-color}; --primary-color: #{$primary-color};
--toolbar-background: #{$toolbar-background}; --toolbar-background: #{$toolbar-background};
--toolbar-color: #{$toolbar-color}; --toolbar-color: #{$toolbar-color};
--main-background: #{$main-background}; --main-background: #{$main-background};
--warn-color: #{$warn-color}; --warn-color: #{$warn-color};
--success-color: #{$success-color};
--divider-color: #{$divider-color};
--dialog-background: #{$dialog-background};
.mat-toolbar{ .mat-toolbar{
background-color: var(--toolbar-background); background-color: var(--toolbar-background);
color: var(--toolbar-color); color: var(--toolbar-color);

View File

@ -0,0 +1,61 @@
.form-group{
display: flex;
flex-wrap: wrap;
margin: 1rem;
&:not(:last-child){
margin-bottom: 2rem;
}
.form-row{
display: flex;
flex-wrap: wrap;
width: 100%;
border-bottom: 1px solid var(--divider-color);
padding-top: 0.75rem;
&:last-child{
border-bottom: 0px;
}
.form-label{
padding-top: 0.75rem;
}
&.form-row-400{
max-width: 400px;
}
> *{
flex-grow: 1;
}
.width-200{
flex-grow: inherit;
width: 200px;
}
}
}
.full-height-form{
height: 100%;
display: flex;
flex-direction: column;
.form-content{
flex-grow: 1;
padding: 0.5rem;
}
.form-footer{
background: var(--dialog-background);
border-top: 1px solid var(--divider-color);
padding: 0.5rem;
display: flex;
justify-content: flex-end;
> div{
display: flex;
&:first-child{
flex-grow: 1;
}
}
}
}
.scrollable-content{
overflow: auto;
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
}

View File

@ -16,6 +16,7 @@ $theme-accent: mat.define-palette(mat.$green-palette, A200, A100, A400);
// The warn palette is optional (defaults to red). // The warn palette is optional (defaults to red).
$theme-warn: mat.define-palette(mat.$red-palette); $theme-warn: mat.define-palette(mat.$red-palette);
$theme-success: mat.define-palette(mat.$green-palette);
// Create the theme object. A theme consists of configurations for individual // Create the theme object. A theme consists of configurations for individual
// theming systems such as "color" or "typography". // theming systems such as "color" or "typography".
@ -24,6 +25,7 @@ $theme: mat.define-dark-theme((
primary: $theme-primary, primary: $theme-primary,
accent: $theme-accent, accent: $theme-accent,
warn: $theme-warn, warn: $theme-warn,
success: $theme-success,
) )
)); ));

View File

@ -17,6 +17,7 @@ $theme-accent: mat.define-palette(mat.$light-blue-palette, A200, A100, A400);
// The warn palette is optional (defaults to red). // The warn palette is optional (defaults to red).
$theme-warn: mat.define-palette(mat.$red-palette); $theme-warn: mat.define-palette(mat.$red-palette);
$theme-success: mat.define-palette(mat.$green-palette);
// Create the theme object. A theme consists of configurations for individual // Create the theme object. A theme consists of configurations for individual
// theming systems such as "color" or "typography". // theming systems such as "color" or "typography".
@ -25,6 +26,7 @@ $theme: mat.define-light-theme((
primary: $theme-primary, primary: $theme-primary,
accent: $theme-accent, accent: $theme-accent,
warn: $theme-warn, warn: $theme-warn,
success: $theme-success,
) )
)); ));

View File

@ -1,8 +1,11 @@
{ {
"APP": { "APP": {
"NAME": "CureNet", "NAME": "App",
"THEME": "Theme", "THEME": "Theme",
"LANGUAGE": "Language" "LANGUAGE": "Language",
"LOGOUT": "Logout",
"USER_SETTINGS": "User settings",
"USER_SITE_SETTINGS": "Site settings"
}, },
"ERROR": { "ERROR": {
"PAGE_NOT_FOUND": "Page not found or not implemented yet!" "PAGE_NOT_FOUND": "Page not found or not implemented yet!"
@ -40,10 +43,20 @@
"RESTORE_ACCOUNT": "Restore account" "RESTORE_ACCOUNT": "Restore account"
}, },
"PROFILE": { "PROFILE": {
"HEALTH": "Health",
"ROLES": "Roles",
"BASICS": "Basic information", "BASICS": "Basic information",
"CONTACT": "Contact information", "CONTACT": "Contact information",
"AVATAR": "Avatar", "AVATAR": "Avatar",
"PASSWORD": "Password", "PASSWORD": "Password",
"SITE_SETTINGS": "Site settings" "SITE_SETTINGS": "Site settings",
"CONTACTS": {
"COUNTRY": "Country",
"STATE": "State",
"CITY": "City",
"ZIP": "Zip code",
"PHONES": "Phone numbers",
"EMAILS": "Email addresses"
}
} }
} }

View File

@ -1,8 +1,11 @@
{ {
"APP": { "APP": {
"NAME": "CureNet", "NAME": "App",
"THEME": "Motyw", "THEME": "Motyw",
"LANGUAGE": "Język" "LANGUAGE": "Język",
"LOGOUT": "Wyloguj",
"USER_SETTINGS": "Ustawienia konta",
"USER_SITE_SETTINGS": "Ustawienia strony"
}, },
"ERROR": { "ERROR": {
"PAGE_NOT_FOUND": "Nie znaleziono strony lub nie została ona jeszcze zaimplementowana!" "PAGE_NOT_FOUND": "Nie znaleziono strony lub nie została ona jeszcze zaimplementowana!"
@ -40,10 +43,20 @@
"RESTORE_ACCOUNT": "Odzyskaj konto" "RESTORE_ACCOUNT": "Odzyskaj konto"
}, },
"PROFILE": { "PROFILE": {
"HEALTH": "Zdrowie",
"ROLES": "Role",
"BASICS": "Podstawowe informacje", "BASICS": "Podstawowe informacje",
"CONTACT": "Dane kontaktowe", "CONTACT": "Dane kontaktowe",
"AVATAR": "Zdjęcie profilowe", "AVATAR": "Zdjęcie profilowe",
"PASSWORD": "Hasło", "PASSWORD": "Hasło",
"SITE_SETTINGS": "Ustawienia strony" "SITE_SETTINGS": "Ustawienia strony",
"CONTACTS": {
"COUNTRY": "Kraj",
"STATE": "Województwo",
"CITY": "Miasto",
"ZIP": "Kod pocztowy",
"PHONES": "Numery telefonów",
"EMAILS": "Adresy email"
}
} }
} }

View File

@ -5,6 +5,7 @@ body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
@import "~bootstrap/dist/css/bootstrap.css"; @import "~bootstrap/dist/css/bootstrap.css";
@import "~font-awesome/css/font-awesome.css"; @import "~font-awesome/css/font-awesome.css";
@import "./app/styles/bundles/form.scss";
body .mat-drawer.mat-drawer-side { body .mat-drawer.mat-drawer-side {
visibility: visible !important; visibility: visible !important;
@ -44,7 +45,45 @@ body .mat-drawer.mat-drawer-side {
width: 220px; width: 220px;
} }
[required]:after{ [required]:after{
content: "*"; content: " *";
font-weight: bold; font-weight: bold;
color: var(--warn-color); color: var(--warn-color);
} }
body .mat-drawer-content{
display: flex;
flex-direction: column;
}
.notify-error{
border-left: 5px solid var(--warn-color);
.mat-simple-snackbar-action{
color: var(--warn-color);
}
}
.notify-success{
border-left: 5px solid var(--success-color);
.mat-simple-snackbar-action{
color: var(--success-color);
}
}
button[is-working]{
position: relative;
&,
& *{
color: transparent;
}
&:before{
font-family: "FontAwesome";
content: "\f013";
display: flex;
position: absolute;
top: 50%;
left: 50%;
width: 20px;
height: 20px;
margin: -10px;
font-size: inherit;
align-items: center;
justify-content: center;
animation: fa-spin 2s infinite linear;
}
}

1
tools/country-list/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.cache

View File

@ -0,0 +1,93 @@
<?php
$countries = [];
$states = [];
$countryId = 0;
$stateId = 0;
class Country {
public int $id;
public function __construct(
public string $code,
public string $name,
public ?string $localeName,
public ?string $subname,
public bool $haveSubregions = false) {
global $countryId;
$this->id = ++$countryId;
}
}
class State {
public int $id;
public function __construct(
public string $code,
public string $name,
public string $countryCode,
public int $countryId,
) {
global $stateId;
$this->id = ++$stateId;
}
}
function get_url($url) {
$cacheFile = './.cache/'.md5($url);
if (file_exists($cacheFile)) {
return file_get_contents($cacheFile);
}
$content = file_get_contents($url);
file_put_contents($cacheFile, $content);
return $content;
}
$content = get_url('https://unece.org/trade/uncefact/unlocode-country-subdivisions-iso-3166-2');
if (preg_match_all('/<td ([^>]{1,})>([a-z]{1,4})<\/td>([^<]{0,})<td ([^>]{1,})>(.*?)<\/td>/i', $content, $matches)) {
foreach ($matches[0] as $mid => $m) {
$name = strip_tags($matches[5][$mid]);
$subname = null;
$a = strpos($name, ',');
if ($a !== false) {
$subname = trim(substr($name, $a+1));
$name = mb_substr($name, 0, $a);
}
$country = new Country(
code: $matches[2][$mid],
name: html_entity_decode(trim($name)),
localeName: null,
subname: $subname,
haveSubregions: strpos($matches[5][$mid], '<a href=') !== false,
);
if ($country->code === 'PL') {
$country->localeName = 'Polska';
}
$countries[] = $country;
}
}
$i = 0;
$count = sizeof($countries);
foreach ($countries as $country) {
if ($country->haveSubregions) {
$code = strtolower($country->code);
$url = 'https://unece.org/DAM/cefact/locode/Subdivision/'. $code .'Sub.htm';
$content = str_replace('&nbsp;',' ', get_url($url));
if (preg_match_all('/<td ([^>]{1,})>([^>]{2,14})<\/td>([^<]{0,})<td ([^>]{1,})>(.*?)<\/td>([^<]{0,})<td ([^>]{1,})>(.*?)<\/td>/i', $content, $matches)) {
foreach ($matches[0] as $mid => $m) {
$states[] = new State(
code: trim($matches[5][$mid]),
name: html_entity_decode(trim($matches[8][$mid])),
countryCode: $country->code,
countryId: $country->id,
);
}
}
$i++;
echo round(100*$i/$count, 2)."% $country->name\n";
} else {
$i++;
}
}
$dir = dirname(__FILE__, 3). '/src/backend/data';
file_put_contents($dir.'/countries.json', json_encode($countries, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
file_put_contents($dir.'/states.json', json_encode($states, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,269 @@
// coutries
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (1, "Afghanistan", NULL, "AF")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (2, "Åland Islands", NULL, "AX")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (3, "Albania", NULL, "AL")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (4, "Algeria", NULL, "DZ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (5, "American Samoa", NULL, "AS")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (6, "Andorra", NULL, "AD")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (7, "Angola", NULL, "AO")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (8, "Anguilla", NULL, "AI")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (9, "Antarctica", NULL, "AQ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (10, "Antigua and Barbuda", NULL, "AG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (11, "Argentina", NULL, "AR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (12, "Armenia", NULL, "AM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (13, "Aruba", NULL, "AW")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (14, "Australia", NULL, "AU")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (15, "Austria", NULL, "AT")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (16, "Azerbaijan", NULL, "AZ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (17, "Bahamas", NULL, "BS")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (18, "Bahrain", NULL, "BH")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (19, "Bangladesh", NULL, "BD")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (20, "Barbados", NULL, "BB")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (21, "Belarus", NULL, "BY")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (22, "Belgium", NULL, "BE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (23, "Belize", NULL, "BZ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (24, "Benin", NULL, "BJ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (25, "Bermuda", NULL, "BM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (26, "Bhutan", NULL, "BT")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (27, "Bolivia", "Plurinational State of", "BO")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (28, "Bonaire", "Sint Eustatius and Saba", "BQ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (29, "Bosnia and Herzegovina", NULL, "BA")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (30, "Botswana", NULL, "BW")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (31, "Bouvet Island", NULL, "BV")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (32, "Brazil", NULL, "BR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (33, "British Indian Ocean Territory", NULL, "IO")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (34, "Brunei Darussalam", NULL, "BN")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (35, "Bulgaria", NULL, "BG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (36, "Burkina Faso", NULL, "BF")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (37, "Burundi", NULL, "BI")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (38, "Cambodia", NULL, "KH")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (39, "Cameroon", NULL, "CM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (40, "Canada", NULL, "CA")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (41, "Cape Verde", NULL, "CV")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (42, "Cayman Islands", NULL, "KY")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (43, "Central African Republic", NULL, "CF")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (44, "Chad", NULL, "TD")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (45, "Chile", NULL, "CL")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (46, "China", NULL, "CN")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (47, "Christmas Island", NULL, "CX")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (48, "Cocos (Keeling) Islands", NULL, "CC")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (49, "Colombia", NULL, "CO")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (50, "Comoros", NULL, "KM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (51, "Congo", NULL, "CG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (52, "Congo", "The Democratic Republic of the", "CD")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (53, "Cook Islands", NULL, "CK")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (54, "Costa Rica", NULL, "CR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (55, "Côte D\\\'Ivoire", NULL, "CI")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (56, "Croatia", NULL, "HR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (57, "Cuba", NULL, "CU")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (58, "Curaçao", NULL, "CW")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (59, "Cyprus", NULL, "CY")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (60, "Czech Republic", NULL, "CZ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (61, "Denmark", NULL, "DK")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (62, "Djibouti", NULL, "DJ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (63, "Dominica", NULL, "DM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (64, "Dominican Republic", NULL, "DO")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (65, "Ecuador", NULL, "EC")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (66, "Egypt", NULL, "EG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (67, "El Salvador", NULL, "SV")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (68, "Equatorial Guinea", NULL, "GQ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (69, "Eritrea", NULL, "ER")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (70, "Estonia", NULL, "EE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (71, "Ethiopia", NULL, "ET")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (72, "Falkland Islands (Malvinas)", NULL, "FK")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (73, "Faroe Islands", NULL, "FO")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (74, "Fiji", NULL, "FJ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (75, "Finland", NULL, "FI")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (76, "France", NULL, "FR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (77, "French Guiana", NULL, "GF")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (78, "French Polynesia", NULL, "PF")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (79, "French Southern Territories", NULL, "TF")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (80, "Gabon", NULL, "GA")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (81, "Gambia", NULL, "GM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (82, "Georgia", NULL, "GE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (83, "Germany", NULL, "DE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (84, "Ghana", NULL, "GH")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (85, "Gibraltar", NULL, "GI")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (86, "Greece", NULL, "GR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (87, "Greenland", NULL, "GL")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (88, "Grenada", NULL, "GD")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (89, "Guadeloupe", NULL, "GP")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (90, "Guam", NULL, "GU")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (91, "Guatemala", NULL, "GT")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (92, "Guernsey", NULL, "GG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (93, "Guinea", NULL, "GN")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (94, "Guinea-Bissau", NULL, "GW")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (95, "Guyana", NULL, "GY")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (96, "Haiti", NULL, "HT")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (97, "Heard Island and Mcdonald Islands", NULL, "HM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (98, "Holy See (Vatican City State)", NULL, "VA")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (99, "Honduras", NULL, "HN")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (100, "Hong Kong", NULL, "HK")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (101, "Hungary", NULL, "HU")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (102, "Iceland", NULL, "IS")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (103, "India", NULL, "IN")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (104, "Indonesia", NULL, "ID")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (105, "Iran", "Islamic Republic of", "IR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (106, "Iraq", NULL, "IQ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (107, "Ireland", NULL, "IE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (108, "Isle of Man", NULL, "IM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (109, "Israel", NULL, "IL")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (110, "Italy", NULL, "IT")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (111, "Jamaica", NULL, "JM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (112, "Japan", NULL, "JP")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (113, "Jersey", NULL, "JE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (114, "Jordan", NULL, "JO")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (115, "Kazakhstan", NULL, "KZ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (116, "Kenya", NULL, "KE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (117, "Kiribati", NULL, "KI")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (118, "Korea", "Democratic People\\\'s Republic of", "KP")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (119, "Korea", "Republic of", "KR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (120, "Kuwait", NULL, "KW")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (121, "Kyrgyzstan", NULL, "KG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (122, "Lao People\\\'s Democratic Republic", NULL, "LA")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (123, "Latvia", NULL, "LV")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (124, "Lebanon", NULL, "LB")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (125, "Lesotho", NULL, "LS")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (126, "Liberia", NULL, "LR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (127, "Libya", NULL, "LY")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (128, "Liechtenstein", NULL, "LI")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (129, "Lithuania", NULL, "LT")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (130, "Luxembourg", NULL, "LU")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (131, "Macao", NULL, "MO")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (132, "Macedonia", "The former Yugoslav Republic of", "MK")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (133, "Madagascar", NULL, "MG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (134, "Malawi", NULL, "MW")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (135, "Malaysia", NULL, "MY")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (136, "Maldives", NULL, "MV")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (137, "Mali", NULL, "ML")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (138, "Malta", NULL, "MT")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (139, "Marshall Islands", NULL, "MH")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (140, "Martinique", NULL, "MQ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (141, "Mauritania", NULL, "MR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (142, "Mauritius", NULL, "MU")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (143, "Mayotte", NULL, "YT")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (144, "Mexico", NULL, "MX")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (145, "Micronesia", "Federated States of", "FM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (146, "Moldova", "Republic of", "MD")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (147, "Monaco", NULL, "MC")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (148, "Mongolia", NULL, "MN")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (149, "Montenegro", NULL, "ME")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (150, "Montserrat", NULL, "MS")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (151, "Morocco", NULL, "MA")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (152, "Mozambique", NULL, "MZ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (153, "Myanmar", NULL, "MM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (154, "Namibia", NULL, "NA")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (155, "Nauru", NULL, "NR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (156, "Nepal", NULL, "NP")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (157, "Netherlands", NULL, "NL")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (158, "New Caledonia", NULL, "NC")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (159, "New Zealand", NULL, "NZ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (160, "Nicaragua", NULL, "NI")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (161, "Niger", NULL, "NE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (162, "Nigeria", NULL, "NG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (163, "Niue", NULL, "NU")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (164, "Norfolk Island", NULL, "NF")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (165, "Northern Mariana Islands", NULL, "MP")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (166, "Norway", NULL, "NO")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (167, "Oman", NULL, "OM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (168, "Pakistan", NULL, "PK")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (169, "Palau", NULL, "PW")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (170, "Palestine", "State of", "PS")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (171, "Panama", NULL, "PA")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (172, "Papua New Guinea", NULL, "PG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (173, "Paraguay", NULL, "PY")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (174, "Peru", NULL, "PE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (175, "Philippines", NULL, "PH")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (176, "Pitcairn", NULL, "PN")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (177, "Poland", NULL, "PL")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (178, "Portugal", NULL, "PT")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (179, "Puerto Rico", NULL, "PR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (180, "Qatar", NULL, "QA")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (181, "Réunion", NULL, "RE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (182, "Romania", NULL, "RO")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (183, "Russian Federation", NULL, "RU")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (184, "Rwanda", NULL, "RW")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (185, "Saint Barthélemy", NULL, "BL")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (186, "Saint Helena", "Ascension and Tristan da Cunha", "SH")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (187, "Saint Kitts and Nevis", NULL, "KN")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (188, "Saint Lucia", NULL, "LC")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (189, "Saint Martin (French Part)", NULL, "MF")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (190, "Saint Pierre and Miquelon", NULL, "PM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (191, "Saint Vincent and the Grenadines", NULL, "VC")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (192, "Samoa", NULL, "WS")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (193, "San Marino", NULL, "SM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (194, "Sao Tome and Principe", NULL, "ST")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (195, "Saudi Arabia", NULL, "SA")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (196, "Senegal", NULL, "SN")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (197, "Serbia", NULL, "RS")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (198, "Seychelles", NULL, "SC")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (199, "Sierra Leone", NULL, "SL")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (200, "Singapore", NULL, "SG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (201, "Sint Maarten (Dutch Part)", NULL, "SX")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (202, "Slovakia", NULL, "SK")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (203, "Slovenia", NULL, "SI")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (204, "Solomon Islands", NULL, "SB")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (205, "Somalia", NULL, "SO")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (206, "South Africa", NULL, "ZA")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (207, "South Georgia and the South Sandwich Islands", NULL, "GS")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (208, "South Sudan", NULL, "SS")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (209, "Spain", NULL, "ES")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (210, "Sri Lanka", NULL, "LK")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (211, "Sudan", NULL, "SD")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (212, "Suriname", NULL, "SR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (213, "Svalbard and Jan Mayen", NULL, "SJ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (214, "Swaziland", NULL, "SZ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (215, "Sweden", NULL, "SE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (216, "Switzerland", NULL, "CH")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (217, "Syrian Arab Republic", NULL, "SY")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (218, "Taiwan", "Province of China", "TW")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (219, "Tajikistan", NULL, "TJ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (220, "Tanzania", "United Republic of", "TZ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (221, "Thailand", NULL, "TH")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (222, "Timor-Leste", NULL, "TL")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (223, "Togo", NULL, "TG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (224, "Tokelau", NULL, "TK")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (225, "Tonga", NULL, "TO")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (226, "Trinidad and Tobago", NULL, "TT")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (227, "Tunisia", NULL, "TN")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (228, "Turkey", NULL, "TR")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (229, "Turkmenistan", NULL, "TM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (230, "Turks and Caicos Islands", NULL, "TC")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (231, "Tuvalu", NULL, "TV")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (232, "Uganda", NULL, "UG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (233, "Ukraine", NULL, "UA")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (234, "United Arab Emirates", NULL, "AE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (235, "United Kingdom", NULL, "GB")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (236, "United States", NULL, "US")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (237, "United States Minor Outlying Islands", NULL, "UM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (238, "Uruguay", NULL, "UY")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (239, "Uzbekistan", NULL, "UZ")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (240, "Vanuatu", NULL, "VU")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (241, "Venezuela", "Bolivarian Republic of", "VE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (242, "Viet Nam", NULL, "VN")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (243, "Virgin Islands", "British", "VG")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (244, "Virgin Islands", "U.S.", "VI")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (245, "Wallis and Futuna", NULL, "WF")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (246, "Western Sahara", NULL, "EH")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (247, "Yemen", NULL, "YE")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (248, "Zambia", NULL, "ZM")');
$this->addSql('INSERT INTO country (id, name, subname, code) VALUES (249, "Zimbabwe", NULL, "ZW")');
// states
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (1, \'Dolnoslaskie\', \'DS\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (2, \'Kujawsko-pomorskie\', \'KP\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (3, \'Lubuskie\', \'LB\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (4, \'Lódzkie\', \'LD\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (5, \'Lubelskie\', \'LU\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (6, \'Malopolskie\', \'MA\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (7, \'Mazowieckie\', \'MZ\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (8, \'Opolskie\', \'OP\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (9, \'Podlaskie\', \'PD\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (10, \'Podkarpackie\', \'PK\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (11, \'Pomorskie\', \'PM\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (12, \'Swietokrzyskie\', \'SK\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (13, \'Slaskie\', \'SL\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (14, \'Warminsko-mazurskie\', \'WN\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (15, \'Wielkopolskie\', \'WP\', 177)');
$this->addSql('INSERT INTO country_region (id, name, code, country) VALUES (16, \'Zachodniopomorskie\', \'ZP\', 177)');

View File

@ -0,0 +1,114 @@
[
{
"id": 1,
"code": "DS",
"name": "Dolnoslaskie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 2,
"code": "KP",
"name": "Kujawsko-pomorskie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 3,
"code": "LB",
"name": "Lubuskie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 4,
"code": "LD",
"name": "Lódzkie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 5,
"code": "LU",
"name": "Lubelskie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 6,
"code": "MA",
"name": "Malopolskie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 7,
"code": "MZ",
"name": "Mazowieckie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 8,
"code": "OP",
"name": "Opolskie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 9,
"code": "PD",
"name": "Podlaskie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 10,
"code": "PK",
"name": "Podkarpackie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 11,
"code": "PM",
"name": "Pomorskie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 12,
"code": "SK",
"name": "Swietokrzyskie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 13,
"code": "SL",
"name": "Slaskie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 14,
"code": "WN",
"name": "Warminsko-mazurskie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 15,
"code": "WP",
"name": "Wielkopolskie",
"countryCode": "PL",
"countryId": 177
},
{
"id": 16,
"code": "ZP",
"name": "Zachodniopomorskie",
"countryCode": "PL",
"countryId": 177
}
]