Compare commits
19
Commits
c0bc89083d
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a9316ed6f | ||
|
|
f3b1d901a8 | ||
|
|
df7e8827be | ||
|
|
2e477ca023 | ||
|
|
5292b99af6 | ||
|
|
3d83e95613 | ||
|
|
75b49be476 | ||
|
|
ba4976fce4 | ||
|
|
4eafa2fa8d | ||
|
|
70083f1230 | ||
|
|
9070bebb54 | ||
|
|
5d2e989ee9 | ||
|
|
ce2b3ba8c9 | ||
|
|
c9228950d5 | ||
|
|
2e7f9e7a27 | ||
|
|
d656229ab3 | ||
|
|
fa3b289a77 | ||
|
|
09ac6c6bb1 | ||
|
|
8228ff27b8 |
+75
-75
@@ -1,75 +1,75 @@
|
|||||||
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.rsuser
|
*.rsuser
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
*.userosscache
|
*.userosscache
|
||||||
*.sln.docstates
|
*.sln.docstates
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
*.userprefs
|
*.userprefs
|
||||||
|
|
||||||
# Mono auto generated files
|
# Mono auto generated files
|
||||||
mono_crash.*
|
mono_crash.*
|
||||||
|
|
||||||
# Build results
|
# Build results
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
[Dd]ebugPublic/
|
[Dd]ebugPublic/
|
||||||
[Rr]elease/
|
[Rr]elease/
|
||||||
[Rr]eleases/
|
[Rr]eleases/
|
||||||
myZip/
|
myZip/
|
||||||
x64/
|
x64/
|
||||||
x86/
|
x86/
|
||||||
[Ww][Ii][Nn]32/
|
[Ww][Ii][Nn]32/
|
||||||
[Aa][Rr][Mm]/
|
[Aa][Rr][Mm]/
|
||||||
[Aa][Rr][Mm]64/
|
[Aa][Rr][Mm]64/
|
||||||
bld/
|
bld/
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
[Oo]ut/
|
[Oo]ut/
|
||||||
[Ll]og/
|
[Ll]og/
|
||||||
[Ll]ogs/
|
[Ll]ogs/
|
||||||
# Compiled output
|
# Compiled output
|
||||||
dist/
|
dist/
|
||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
tmp/
|
tmp/
|
||||||
**/out-tsc
|
**/out-tsc
|
||||||
**/bazel-out
|
**/bazel-out
|
||||||
|
|
||||||
# Node
|
# Node
|
||||||
**/node_modules
|
**/node_modules
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
|
||||||
# IDEs and editors
|
# IDEs and editors
|
||||||
.idea/
|
.idea/
|
||||||
.project
|
.project
|
||||||
.classpath
|
.classpath
|
||||||
.c9/
|
.c9/
|
||||||
*.launch
|
*.launch
|
||||||
.settings/
|
.settings/
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
|
|
||||||
# Visual Studio Code
|
# Visual Studio Code
|
||||||
.vscode/*
|
.vscode/*
|
||||||
.vs/
|
.vs/
|
||||||
!.vscode/settings.json
|
!.vscode/settings.json
|
||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
.history/*
|
.history/*
|
||||||
|
|
||||||
# Miscellaneous
|
# Miscellaneous
|
||||||
**/.angular/cache
|
**/.angular/cache
|
||||||
.sass-cache/
|
.sass-cache/
|
||||||
/connect.lock
|
/connect.lock
|
||||||
/coverage
|
/coverage
|
||||||
/libpeerconnection.log
|
/libpeerconnection.log
|
||||||
testem.log
|
testem.log
|
||||||
/typings
|
/typings
|
||||||
|
|
||||||
# System files
|
# System files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
/API/FamilyTreeAPI/uploads
|
/API/FamilyTreeAPI/uploads
|
||||||
|
|||||||
Vendored
+54
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "C#: FamilyTreeAPI",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
"program": "${workspaceFolder}/FamilyTreeAPI/bin/Debug/net10.0/FamilyTreeAPI.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"console": "internalConsole",
|
||||||
|
|
||||||
|
"env": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||||
|
"ASPNETCORE_URLS": "http://localhost:5019"
|
||||||
|
},
|
||||||
|
"serverReadyAction": {
|
||||||
|
"action": "openExternally",
|
||||||
|
"pattern": "\\bNow listening on:\\s+(https?://\\S+)",
|
||||||
|
"uriFormat": "%s/swagger/index.html"
|
||||||
|
},
|
||||||
|
|
||||||
|
"sourceFileMap": {
|
||||||
|
"/Views": "${workspaceFolder}/Views"
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ".NET Core Launch (web) - Release",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "publish",
|
||||||
|
"program": "${workspaceFolder}/FamilyTreeAPI/bin/Release/net10.0/linux-x64/FamilyTreeAPI.dll",
|
||||||
|
"serverReadyAction": {
|
||||||
|
"action": "openExternally",
|
||||||
|
"pattern": "listening on:\\s+(https?://\\S+)",
|
||||||
|
"uriFormat": "%s/swagger/index.html"
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Production",
|
||||||
|
"ASPNETCORE_URLS": "https://localhost:5019"
|
||||||
|
},
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+31
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "shell",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/FamilyTreeAPI/FamilyTreeAPI.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/FamilyTreeAPI/FamilyTreeAPI.csproj",
|
||||||
|
"-c",
|
||||||
|
"Release"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.7.34202.233
|
VisualStudioVersion = 17.7.34202.233
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using FamilyTreeAPI.Repository;
|
|||||||
|
|
||||||
namespace FamilyTreeAPI.Controllers;
|
namespace FamilyTreeAPI.Controllers;
|
||||||
|
|
||||||
|
using DocumentFormat.OpenXml.Drawing.Charts;
|
||||||
using FamilyTreeAPI.Interface;
|
using FamilyTreeAPI.Interface;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
@@ -110,14 +111,44 @@ public class FileUploadController : ControllerBase
|
|||||||
return Ok(ret);
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("[action]")]
|
||||||
|
public async Task<IActionResult> DownloadPersonPhotoById(DeleteCriteria<int> criteria)
|
||||||
|
{
|
||||||
|
|
||||||
|
var result = await _personPhoto.DownloadPersonPhotoById(criteria.Id);
|
||||||
|
if (result.StatusCode > 0)
|
||||||
|
return File(result.Data.Content, result.Data.ContentType, result.Data.FileName);
|
||||||
|
else
|
||||||
|
return NotFound("not found image");
|
||||||
|
}
|
||||||
[HttpPost("[action]")]
|
[HttpPost("[action]")]
|
||||||
public async Task<IActionResult> DownloadPersonPhoto(DownloadFileCriteria criteria)
|
public async Task<IActionResult> DownloadPersonPhoto(DownloadFileCriteria criteria)
|
||||||
{
|
{
|
||||||
|
|
||||||
var result = await _personPhoto.DownloadPersonPhoto(criteria.Id, criteria.FileName);
|
var result = await _personPhoto.DownloadPersonPhotoPerson(criteria.Id,criteria.PhotoType ,criteria.FileName);
|
||||||
|
if (result.StatusCode > 0)
|
||||||
|
return File(result.Data.Content, result.Data.ContentType, result.Data.FileName);
|
||||||
|
else
|
||||||
|
return NotFound("not found image");
|
||||||
|
}
|
||||||
|
[HttpPost("[action]")]
|
||||||
|
public async Task<IActionResult> DownloadPersonPhoto64(DownloadFileCriteria criteria)
|
||||||
|
{
|
||||||
|
|
||||||
return File(result.Data.Content, result.Data.ContentType, result.Data.FileName);
|
var result = await _personPhoto.DownloadPersonPhotoPerson(criteria.Id,criteria.PhotoType ,criteria.FileName);
|
||||||
|
if (result.StatusCode > 0)
|
||||||
|
{
|
||||||
|
byte[] file64 = result.Data.Content;
|
||||||
|
string rval = Convert.ToBase64String(file64);
|
||||||
|
ResultModel<string> retval = new() {
|
||||||
|
Data = rval,
|
||||||
|
StatusCode = 1,
|
||||||
|
Message = ""
|
||||||
|
};
|
||||||
|
return Ok(retval);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NotFound("not found image");
|
||||||
}
|
}
|
||||||
[HttpPost("[action]")]
|
[HttpPost("[action]")]
|
||||||
public async Task<ActionResult> DeletePersonPhoto(DeleteFileCriteria criteria)
|
public async Task<ActionResult> DeletePersonPhoto(DeleteFileCriteria criteria)
|
||||||
@@ -127,8 +158,18 @@ public class FileUploadController : ControllerBase
|
|||||||
if ( criteria.Id > 0)
|
if ( criteria.Id > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
ret = await _personPhoto.DeletePersonPhoto(criteria.Id);
|
ret = await _personPhoto.DeletePersonPhoto(criteria.Id, criteria.PhotoType);
|
||||||
}
|
}
|
||||||
return Ok(ret);
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
|
[HttpPost("[action]")]
|
||||||
|
public async Task<ActionResult> DeletePersonPhotoById(DeleteCriteria<int> criteria)
|
||||||
|
{
|
||||||
|
|
||||||
|
ResultModel<int> ret = new();
|
||||||
|
|
||||||
|
ret = await _personPhoto.DeletePersonPhotoById(criteria.Id);
|
||||||
|
|
||||||
|
return Ok(ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ namespace FamilyTreeAPI.Controllers
|
|||||||
{
|
{
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("[action]")]
|
[HttpPost("[action]")]
|
||||||
public async Task<IActionResult> UploadImage(IFormFile file)
|
public async Task<IActionResult> UploadImage(IFormFile file)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,8 +37,25 @@ public class UsersController : ControllerBase
|
|||||||
public async Task<IActionResult> LoginApiAD([FromBody] AuthenticateRequest model)
|
public async Task<IActionResult> LoginApiAD([FromBody] AuthenticateRequest model)
|
||||||
{
|
{
|
||||||
string remoteIpAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
|
string remoteIpAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||||
var response = await _userService.LoginApiAD(model, remoteIpAddress);
|
var rval = await _userService.LoginApiAD(model, remoteIpAddress);
|
||||||
return Ok(response);
|
if (rval.Data != null && rval.Data.Token != null)
|
||||||
|
{
|
||||||
|
// Configure cookie options
|
||||||
|
|
||||||
|
var cookieOptions = new CookieOptions
|
||||||
|
{
|
||||||
|
HttpOnly = true, // Blocks client-side JavaScript reading/theft
|
||||||
|
Secure = false, // Requires HTTPS connections
|
||||||
|
SameSite = SameSiteMode.Unspecified, // Prevents CSRF attacks
|
||||||
|
Expires = DateTimeOffset.UtcNow.AddDays(1), // Match your token lifespan
|
||||||
|
Path = "/" // Accessible across entire domain structure
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write cookie into response headers
|
||||||
|
Response.Cookies.Append("token", rval.Data.Token, cookieOptions);
|
||||||
|
}
|
||||||
|
return Ok(rval);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("[action]")]
|
[HttpPost("[action]")]
|
||||||
@@ -51,6 +68,14 @@ public class UsersController : ControllerBase
|
|||||||
string token = Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
|
string token = Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
|
||||||
string remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString();
|
string remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString();
|
||||||
var response = await _userService.Logout(token, currentUser, remoteIpAddress);
|
var response = await _userService.Logout(token, currentUser, remoteIpAddress);
|
||||||
|
Response.Cookies.Delete("token", new CookieOptions
|
||||||
|
{
|
||||||
|
HttpOnly = true,
|
||||||
|
Secure = false,
|
||||||
|
SameSite = SameSiteMode.Unspecified,
|
||||||
|
Path = "/"
|
||||||
|
});
|
||||||
|
|
||||||
return Ok(response);
|
return Ok(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# This stage is used when running from VS in fast mode (Default for Debug configuration)
|
# This stage is used when running from VS in fast mode (Default for Debug configuration)
|
||||||
#FROM mcr.microsoft.com/dotnet/aspnet:9::.0 AS base
|
#FROM mcr.microsoft.com/dotnet/aspnet:9::.0 AS base
|
||||||
ARG BUILD_CONFIGURATION=Release
|
ARG BUILD_CONFIGURATION=Release
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY ["FamilyTreeAPI/FamilyTreeAPI.csproj", "FamilyTreeAPI/"]
|
COPY ["FamilyTreeAPI/FamilyTreeAPI.csproj", "FamilyTreeAPI/"]
|
||||||
RUN dotnet restore "./FamilyTreeAPI/FamilyTreeAPI.csproj"
|
RUN dotnet restore "./FamilyTreeAPI/FamilyTreeAPI.csproj"
|
||||||
@@ -31,7 +31,7 @@ FROM build AS publish
|
|||||||
RUN dotnet publish "./FamilyTreeAPI.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
RUN dotnet publish "./FamilyTreeAPI.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
|
# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV ASPNETCORE_HTTP_PORTS=8080
|
ENV ASPNETCORE_HTTP_PORTS=8080
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|||||||
@@ -15,16 +15,19 @@ public class DownloadFileCriteria
|
|||||||
{
|
{
|
||||||
public string FileName { get; set; }
|
public string FileName { get; set; }
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public int PhotoType {get; set;}
|
||||||
}
|
}
|
||||||
public class UploadCriteria
|
public class UploadCriteria
|
||||||
{
|
{
|
||||||
public string FileName { get; set; }
|
public string FileName { get; set; }
|
||||||
public int PersonId { get; set; }
|
public int PersonId { get; set; }
|
||||||
|
public int PhotoType {get; set;}
|
||||||
public IFormFile File { get; set; }
|
public IFormFile File { get; set; }
|
||||||
}
|
}
|
||||||
public class DeleteFileCriteria
|
public class DeleteFileCriteria
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Filename { get; set; }
|
public string Filename { get; set; }
|
||||||
|
public int PhotoType {get; set;}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,12 @@
|
|||||||
namespace FamilyTreeAPI.Entities;
|
namespace FamilyTreeAPI.Entities;
|
||||||
|
|
||||||
|
|
||||||
|
//photo Type string number
|
||||||
|
public enum enumPhotoType
|
||||||
|
{
|
||||||
|
Profile = 1,
|
||||||
|
Other = 2
|
||||||
|
}
|
||||||
public class PersonPhotoDto
|
public class PersonPhotoDto
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
@@ -7,28 +6,36 @@
|
|||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
<PublishSingleFile>true</PublishSingleFile>
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
|
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
|
<AllowMissingPrunePackageData>true</AllowMissingPrunePackageData>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="HotChocolate.AspNetCore" Version="16.0.0" />
|
<PackageReference Include="HotChocolate.AspNetCore" Version="16.6.1" />
|
||||||
<PackageReference Include="HotChocolate.Data.EntityFramework" Version="16.0.0" />
|
<PackageReference Include="HotChocolate.Data.EntityFramework" Version="16.6.1" />
|
||||||
<PackageReference Include="HotChocolate.Pagination.EntityFramework" Version="14.3.1" />
|
<PackageReference Include="HotChocolate.Pagination.EntityFramework" Version="14.3.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.7" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.11" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.7" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.11" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.11">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.7">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.11">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.3" />
|
||||||
<PackageReference Include="SpreadsheetLight" Version="3.5.0" />
|
<PackageReference Include="SpreadsheetLight" Version="3.5.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.7" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.3" />
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="10.0.11" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="appsettings.Development.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
{
|
{
|
||||||
public class Helpers
|
public class Helpers
|
||||||
{
|
{
|
||||||
|
public static string GetFileExtension(string fileName)
|
||||||
|
{
|
||||||
|
string result = System.IO.Path.GetExtension(fileName);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
public static string GetFileContent(string extension)
|
public static string GetFileContent(string extension)
|
||||||
{
|
{
|
||||||
string contentType = "";
|
string contentType = "";
|
||||||
@@ -82,7 +88,7 @@
|
|||||||
if (date.HasValue)
|
if (date.HasValue)
|
||||||
{
|
{
|
||||||
result = date.Value.ToString("yyyy-MM-dd");
|
result = date.Value.ToString("yyyy-MM-dd");
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public static DateTime? DateToDateTime(string? date)
|
public static DateTime? DateToDateTime(string? date)
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ namespace FamilyTreeAPI.Interface;
|
|||||||
public interface IPersonPhoto
|
public interface IPersonPhoto
|
||||||
{
|
{
|
||||||
Task<ResultModel<int>> SaveAsync(UploadCriteria criteria);
|
Task<ResultModel<int>> SaveAsync(UploadCriteria criteria);
|
||||||
Task<ResultModel<FileContent>> DownloadPersonPhoto(int id, string? filename);
|
Task<ResultModel<FileContent>> DownloadPersonPhotoPerson(int personId, int photoType, string filename);
|
||||||
|
Task<ResultModel<FileContent>> DownloadPersonPhotoById(int id);
|
||||||
Task<ResultModel<int>> DeletePersonPhoto(int id);
|
Task<ResultModel<int>> DeletePersonPhoto(int id, int photoType);
|
||||||
|
Task<ResultModel<int>> DeletePersonPhotoById(int id);
|
||||||
Task<ResultModel<List<PersonPhotoDto>>> LoadPersonPhoto(int personId);
|
Task<ResultModel<List<PersonPhotoDto>>> LoadPersonPhoto(int personId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Storage;
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using DocumentFormat.OpenXml.Office2010.Drawing.Charts;
|
|
||||||
using FamilyTreeAPI.Authorization;
|
using FamilyTreeAPI.Authorization;
|
||||||
using FamilyTreeAPI.Entities;
|
using FamilyTreeAPI.Entities;
|
||||||
using FamilyTreeAPI.GraphQL.Query;
|
using FamilyTreeAPI.GraphQL.Query;
|
||||||
@@ -14,6 +13,15 @@ using FamilyTreeAPI.Repository;
|
|||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
builder.Logging.ClearProviders();
|
||||||
|
builder.Logging.AddConsole();
|
||||||
|
builder.Logging.AddDebug();
|
||||||
|
// Explicitly register the base paths for Linux container execution
|
||||||
|
builder.Configuration
|
||||||
|
.SetBasePath(AppContext.BaseDirectory) // <-- Pulls from wherever the binary sits
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
#region Services
|
#region Services
|
||||||
var services = builder.Services;
|
var services = builder.Services;
|
||||||
@@ -22,19 +30,25 @@ services.AddControllers();
|
|||||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
services.AddEndpointsApiExplorer();
|
services.AddEndpointsApiExplorer();
|
||||||
services.AddSwaggerGen();
|
services.AddSwaggerGen();
|
||||||
|
string skey = "Super Secret SIGN AND VERIFY JWT TOKENS";
|
||||||
|
|
||||||
|
|
||||||
var appSettingsSection = builder.Configuration.GetSection("AppSettings");
|
var appSettingsSection = builder.Configuration.GetSection("AppSettings");
|
||||||
string skey = "";
|
if (appSettingsSection.Exists())
|
||||||
if (appSettingsSection == null)
|
|
||||||
{
|
|
||||||
skey = builder.Configuration.GetValue<string>("AppSettings:SecretKey");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
services.Configure<AppSettings>(appSettingsSection);
|
services.Configure<AppSettings>(appSettingsSection);
|
||||||
var appSettings = appSettingsSection.Get<AppSettings>();
|
var appSettings = appSettingsSection.Get<AppSettings>();
|
||||||
skey = appSettings.Secret;
|
if ( appSettings != null)
|
||||||
|
skey = appSettings.Secret;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string tkey = builder.Configuration.GetValue<string>("AppSettings:Secret") ?? string.Empty;
|
||||||
|
if (!string.IsNullOrEmpty(tkey))
|
||||||
|
skey = tkey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var key = Encoding.ASCII.GetBytes(skey);
|
var key = Encoding.ASCII.GetBytes(skey);
|
||||||
|
|
||||||
services.AddAuthentication(x =>
|
services.AddAuthentication(x =>
|
||||||
@@ -122,7 +136,16 @@ using (var scope = app.Services.CreateScope())
|
|||||||
//if (!databaseCreator.Exists())
|
//if (!databaseCreator.Exists())
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
databaseCreator.CreateTables();
|
// Check if database exists
|
||||||
|
if (!databaseCreator.Exists())
|
||||||
|
{
|
||||||
|
databaseCreator.Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!databaseCreator.HasTables())
|
||||||
|
{
|
||||||
|
databaseCreator.CreateTables();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -164,6 +187,17 @@ app.Run();
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Update="appsettings.Development.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
|
|
||||||
https://www.youtube.com/watch?v=WQFx2m5Ub9M
|
https://www.youtube.com/watch?v=WQFx2m5Ub9M
|
||||||
|
|
||||||
|
|
||||||
@@ -179,14 +213,43 @@ PM> Scaffold-DbContext "Host=postgresdb;Port=5432;database=FamilyTreeDB;user id=
|
|||||||
https://www.youtube.com/watch?v=HnXA8RI7Tvc
|
https://www.youtube.com/watch?v=HnXA8RI7Tvc
|
||||||
|
|
||||||
query {
|
query {
|
||||||
family {
|
persons {
|
||||||
nodes{
|
nodes{
|
||||||
id
|
id
|
||||||
firstname
|
firstName
|
||||||
lastname
|
sex
|
||||||
email
|
email
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
dotnet --list-sdks
|
||||||
|
|
||||||
|
In the VS Code Explorer, click and open your <ProjectName>.csproj file.
|
||||||
|
Locate the <TargetFramework> tag inside the <PropertyGroup> block.
|
||||||
|
Change the value to your desired version (e.g., change net11.0 or net9.0 to net10.0
|
||||||
|
|
||||||
|
now run to see out of date
|
||||||
|
|
||||||
|
dotnet list package --outdated
|
||||||
|
|
||||||
|
dotnet tool uninstall --global dotnet-outdated
|
||||||
|
dotnet tool install --global dotnet-outdated-tool
|
||||||
|
|
||||||
|
//update the outdate
|
||||||
|
dotnet outdated -u
|
||||||
|
|
||||||
|
update the package
|
||||||
|
dotnet add package <Package_Name>
|
||||||
|
|
||||||
|
Open the .vscode folder in your workspace and select launch.json.
|
||||||
|
Look for lines containing your old framework directory string (e.g., /bin/Debug/net8.0/).
|
||||||
|
Update those paths to reflect your new version (e.g., /bin/Debug/net9.0/).
|
||||||
|
|
||||||
|
clear and rebuild
|
||||||
|
|
||||||
|
dotnet clean
|
||||||
|
dotnet restore
|
||||||
|
dotnet build
|
||||||
|
*/
|
||||||
|
|||||||
@@ -8,35 +8,17 @@
|
|||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
},
|
},
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"applicationUrl": "http://localhost:5016",
|
"applicationUrl": "http://localhost:5016"
|
||||||
"applicationUrl1": "http://192.168.8.188:5015"
|
|
||||||
},
|
},
|
||||||
"IIS Express": {
|
"http": {
|
||||||
"commandName": "IISExpress",
|
"commandName": "Project",
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "swagger",
|
"launchUrl": "swagger",
|
||||||
"environmentVariables": {
|
"applicationUrl": "http://localhost:5000"
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Container (Dockerfile)": {
|
|
||||||
"commandName": "Docker",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_HTTP_PORTS": "8080"
|
|
||||||
},
|
|
||||||
"publishAllPorts": true,
|
|
||||||
"useSSL": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||||
"iisSettings": {
|
|
||||||
"windowsAuthentication": false,
|
|
||||||
"anonymousAuthentication": true,
|
|
||||||
"iisExpress": {
|
|
||||||
"applicationUrl": "http://localhost:4559",
|
|
||||||
"sslPort": 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ using FamilyTreeAPI.Entities;
|
|||||||
using FamilyTreeAPI.Helper;
|
using FamilyTreeAPI.Helper;
|
||||||
using FamilyTreeAPI.Interface;
|
using FamilyTreeAPI.Interface;
|
||||||
using FamilyTreeAPI.Models;
|
using FamilyTreeAPI.Models;
|
||||||
|
using HotChocolate.CostAnalysis.Types;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace FamilyTreeAPI.Repository
|
namespace FamilyTreeAPI.Repository
|
||||||
@@ -31,12 +32,12 @@ namespace FamilyTreeAPI.Repository
|
|||||||
dto.PhotoType = model.PhotoType;
|
dto.PhotoType = model.PhotoType;
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
private PersonPhoto FillModel(PersonPhoto model, int personId, string filename)
|
private PersonPhoto FillModel(PersonPhoto model, int personId, int photoType, string filename)
|
||||||
{
|
{
|
||||||
|
|
||||||
model.PersonId = personId;
|
model.PersonId = personId;
|
||||||
model.Photo = filename;
|
model.Photo = filename;
|
||||||
model.PhotoType = System.IO.Path.GetExtension(filename);
|
model.PhotoType = photoType.ToString(); //System.IO.Path.GetExtension(filename);
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
@@ -44,8 +45,10 @@ namespace FamilyTreeAPI.Repository
|
|||||||
{
|
{
|
||||||
int result = default(int);
|
int result = default(int);
|
||||||
int statuscode = 0;
|
int statuscode = 0;
|
||||||
string error = "";
|
string error = "";//Other
|
||||||
|
string photoType = "2"; //
|
||||||
|
if (criteria.PhotoType > 0)
|
||||||
|
photoType = criteria.PhotoType.ToString();
|
||||||
HttpContext? httpContext = _httpContext.HttpContext;
|
HttpContext? httpContext = _httpContext.HttpContext;
|
||||||
string loginName = "";
|
string loginName = "";
|
||||||
if (httpContext != null)
|
if (httpContext != null)
|
||||||
@@ -63,7 +66,7 @@ namespace FamilyTreeAPI.Repository
|
|||||||
|
|
||||||
model = new();
|
model = new();
|
||||||
|
|
||||||
model = FillModel(model,criteria.PersonId, formfile.FileName);
|
model = FillModel(model,criteria.PersonId, criteria.PhotoType,formfile.FileName);
|
||||||
|
|
||||||
using (var stream = new MemoryStream())
|
using (var stream = new MemoryStream())
|
||||||
{
|
{
|
||||||
@@ -90,15 +93,50 @@ namespace FamilyTreeAPI.Repository
|
|||||||
Message = error
|
Message = error
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
public async Task<ResultModel<FileContent>> DownloadPersonPhotoById(int Id)
|
||||||
public async Task<ResultModel<FileContent>> DownloadPersonPhoto(int id, string? filename)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
int statusCode = -1;
|
int statusCode = -1;
|
||||||
string error = "";
|
string error = "";
|
||||||
|
string extension = "";
|
||||||
PersonPhoto? model = null;
|
PersonPhoto? model = null;
|
||||||
FileContent fileContent = new();
|
FileContent fileContent = new();
|
||||||
if (id < 1)
|
try {
|
||||||
|
|
||||||
|
model = await _context.PersonPhotos.FindAsync(Id);
|
||||||
|
|
||||||
|
|
||||||
|
if (model != null)
|
||||||
|
{
|
||||||
|
extension = Helpers.GetFileExtension(model.Photo);
|
||||||
|
fileContent.ContentType = Helpers.GetFileContent(extension);
|
||||||
|
fileContent.Content = (byte[])model.ImagePhoto;
|
||||||
|
fileContent.FileName = model.Photo;
|
||||||
|
statusCode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
error = e.ToString();
|
||||||
|
statusCode = -1;
|
||||||
|
}
|
||||||
|
return new ResultModel<FileContent>()
|
||||||
|
{
|
||||||
|
Data = fileContent,
|
||||||
|
StatusCode = statusCode,
|
||||||
|
Message = error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ResultModel<FileContent>> DownloadPersonPhotoPerson(int personId, int photoType, string filename)
|
||||||
|
{
|
||||||
|
|
||||||
|
int statusCode = -1;
|
||||||
|
string error = "";
|
||||||
|
string extension = "";
|
||||||
|
PersonPhoto? model = null;
|
||||||
|
FileContent fileContent = new();
|
||||||
|
if (personId < 1)
|
||||||
{
|
{
|
||||||
var rlist = await _context.PersonPhotos.Where(x => x.Photo == filename).ToListAsync();
|
var rlist = await _context.PersonPhotos.Where(x => x.Photo == filename).ToListAsync();
|
||||||
if (rlist != null)
|
if (rlist != null)
|
||||||
@@ -109,19 +147,26 @@ namespace FamilyTreeAPI.Repository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
model = await _context.PersonPhotos.FindAsync(id);
|
var rlist = await _context.PersonPhotos.Where (x => x.PersonId == personId && photoType.ToString() == x.PhotoType).ToListAsync();
|
||||||
}
|
for ( int i = 0; i < rlist.Count; i++)
|
||||||
|
{
|
||||||
|
model = rlist[i];
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (model != null)
|
if (model != null)
|
||||||
{
|
{
|
||||||
fileContent.ContentType = Helpers.GetFileContent(model.PhotoType);
|
extension = Helpers.GetFileExtension(model.Photo);
|
||||||
|
fileContent.ContentType = Helpers.GetFileContent(extension);
|
||||||
fileContent.Content = (byte[])model.ImagePhoto;
|
fileContent.Content = (byte[])model.ImagePhoto;
|
||||||
fileContent.FileName = model.Photo;
|
fileContent.FileName = model.Photo;
|
||||||
statusCode = 1;
|
statusCode = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ResultModel<FileContent>()
|
return new ResultModel<FileContent>()
|
||||||
{
|
{
|
||||||
Data = fileContent,
|
Data = fileContent,
|
||||||
@@ -130,20 +175,69 @@ namespace FamilyTreeAPI.Repository
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ResultModel<int>> DeletePersonPhoto(int id)
|
public async Task<ResultModel<int>> DeletePersonPhoto(int personId, int photoType)
|
||||||
{
|
{
|
||||||
int result = default(int);
|
int result = default(int);
|
||||||
int statuscode = 0;
|
int statuscode = 0;
|
||||||
string error = "";
|
string error = "";
|
||||||
|
PersonPhoto? model;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PersonPhoto? model = await _context.PersonPhotos.FindAsync(id);
|
if (photoType < 1)
|
||||||
if (model != null)
|
|
||||||
{
|
{
|
||||||
_context.PersonPhotos.Remove(model);
|
List<PersonPhoto> list = await _context.PersonPhotos.Where ( x => x.PersonId == personId).ToListAsync();
|
||||||
await _context.SaveChangesAsync();
|
for (int i = 0; i< list.Count; i++)
|
||||||
statuscode = 1;
|
{
|
||||||
|
model = list[i];
|
||||||
|
_context.PersonPhotos.Remove(model);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
statuscode = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<PersonPhoto> list = await _context.PersonPhotos.Where ( x => x.PersonId == personId && x.PhotoType == photoType.ToString()).ToListAsync();
|
||||||
|
for (int i = 0; i< list.Count; i++)
|
||||||
|
{
|
||||||
|
model = list[i];
|
||||||
|
_context.PersonPhotos.Remove(model);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
statuscode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
error = ex.ToString();
|
||||||
|
statuscode = -1;
|
||||||
|
}
|
||||||
|
//var dto = await Task.Run(() => result);
|
||||||
|
return new ResultModel<int>()
|
||||||
|
{
|
||||||
|
Data = result,
|
||||||
|
StatusCode = statuscode,
|
||||||
|
Message = error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ResultModel<int>> DeletePersonPhotoById(int id)
|
||||||
|
{
|
||||||
|
int result = default(int);
|
||||||
|
int statuscode = 0;
|
||||||
|
string error = "";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
PersonPhoto? model = await _context.PersonPhotos.FindAsync(id);
|
||||||
|
if (model != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
_context.PersonPhotos.Remove(model);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
statuscode = 1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ public partial class PersonRepository : IPerson
|
|||||||
node.Key = item.Id.ToString();
|
node.Key = item.Id.ToString();
|
||||||
node.Type = type;
|
node.Type = type;
|
||||||
if (item.Image != null)
|
if (item.Image != null)
|
||||||
node.Data.Image = await LoadPersonImage(item.Image);
|
node.Data.Image = await LoadPersonImage(item.Id, (int) enumPhotoType.Profile, item.Image);
|
||||||
|
|
||||||
node.Icon = "T";
|
node.Icon = "T";
|
||||||
node.StyleClass = getStyleClass(node.Icon);
|
node.StyleClass = getStyleClass(node.Icon);
|
||||||
@@ -319,8 +319,8 @@ public partial class PersonRepository : IPerson
|
|||||||
TreeNode<TreeData> child;
|
TreeNode<TreeData> child;
|
||||||
PersonDto dto;
|
PersonDto dto;
|
||||||
Person pe;
|
Person pe;
|
||||||
int fatherId, motherId;
|
int fatherId, motherId, personId;
|
||||||
fatherId = motherId = 0;
|
personId = fatherId = motherId = 0;
|
||||||
string data = person.Sex;
|
string data = person.Sex;
|
||||||
TreeNode<TreeData> citem;
|
TreeNode<TreeData> citem;
|
||||||
string pName = "";
|
string pName = "";
|
||||||
@@ -371,6 +371,7 @@ public partial class PersonRepository : IPerson
|
|||||||
pName = pe.FirstName;
|
pName = pe.FirstName;
|
||||||
image = pe.Image;
|
image = pe.Image;
|
||||||
key = motherId.ToString();
|
key = motherId.ToString();
|
||||||
|
personId = motherId;
|
||||||
data = pe.Sex;
|
data = pe.Sex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -382,6 +383,7 @@ public partial class PersonRepository : IPerson
|
|||||||
pName = pe.FirstName;
|
pName = pe.FirstName;
|
||||||
image = pe.Image;
|
image = pe.Image;
|
||||||
key = fatherId.ToString();
|
key = fatherId.ToString();
|
||||||
|
personId = fatherId;
|
||||||
data = pe.Sex;
|
data = pe.Sex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -390,7 +392,7 @@ public partial class PersonRepository : IPerson
|
|||||||
citem.Data = new();
|
citem.Data = new();
|
||||||
citem.Label = pName;
|
citem.Label = pName;
|
||||||
if (image != null)
|
if (image != null)
|
||||||
citem.Data.Image = await LoadPersonImage(image);
|
citem.Data.Image = await LoadPersonImage(personId, (int) enumPhotoType.Profile, image);
|
||||||
|
|
||||||
citem.Icon = "P";
|
citem.Icon = "P";
|
||||||
|
|
||||||
@@ -411,7 +413,7 @@ public partial class PersonRepository : IPerson
|
|||||||
child.Type = type;
|
child.Type = type;
|
||||||
image = dto.Image;
|
image = dto.Image;
|
||||||
if (image != null)
|
if (image != null)
|
||||||
child.Data.Image = await LoadPersonImage(image);
|
child.Data.Image = await LoadPersonImage(dto.Id,(int) enumPhotoType.Profile, image);
|
||||||
child.Icon = "C";
|
child.Icon = "C";
|
||||||
child.StyleClass = getStyleClass(child.Icon);
|
child.StyleClass = getStyleClass(child.Icon);
|
||||||
child.Label = dto.FirstName;
|
child.Label = dto.FirstName;
|
||||||
@@ -480,12 +482,12 @@ public partial class PersonRepository : IPerson
|
|||||||
/// <param name="fileName"></param>
|
/// <param name="fileName"></param>
|
||||||
/// <param name="familyId"></param>
|
/// <param name="familyId"></param>
|
||||||
/// <param name="base64"></param>
|
/// <param name="base64"></param>
|
||||||
private string SaveFile(string fileName, int familyId, string base64)
|
private async Task<string> SaveFile(string fileName, int personId, string base64)
|
||||||
{
|
{
|
||||||
string path = "";
|
string path = "";
|
||||||
|
|
||||||
int statusCode = 0;
|
int statusCode = 0;
|
||||||
string error = "";
|
// string error = "";
|
||||||
string sdate = GetCurrentDateTime();
|
string sdate = GetCurrentDateTime();
|
||||||
string filename, extention;
|
string filename, extention;
|
||||||
filename = extention = "";
|
filename = extention = "";
|
||||||
@@ -494,14 +496,33 @@ public partial class PersonRepository : IPerson
|
|||||||
string rbase = base64.Substring(first, last - first);
|
string rbase = base64.Substring(first, last - first);
|
||||||
|
|
||||||
byte[] newBytes = Convert.FromBase64String(rbase);
|
byte[] newBytes = Convert.FromBase64String(rbase);
|
||||||
|
extention = System.IO.Path.GetExtension(fileName);
|
||||||
|
filename = personId + "_" + sdate + extention;
|
||||||
|
|
||||||
|
// Wrap the byte array in a MemoryStream
|
||||||
|
var stream = new MemoryStream(newBytes);
|
||||||
|
|
||||||
|
// Create the IFormFile instance
|
||||||
|
IFormFile file = new FormFile(stream, 0, newBytes.Length, "Profile", filename)
|
||||||
|
{
|
||||||
|
Headers = new HeaderDictionary(),
|
||||||
|
ContentType = "application/octet-stream" // Change to your specific MIME type if known (e.g., "image/jpeg", "application/pdf")
|
||||||
|
};
|
||||||
|
//save to database.
|
||||||
|
UploadCriteria criteria = new();
|
||||||
|
criteria.FileName = filename;
|
||||||
|
criteria.PersonId = personId;
|
||||||
|
criteria.PhotoType = (int) enumPhotoType.Profile;
|
||||||
|
criteria.File = file;
|
||||||
|
var rval = await _personPhoto.SaveAsync(criteria);
|
||||||
|
|
||||||
|
/*
|
||||||
path = _config["AppSettings:ImageFolder"];
|
path = _config["AppSettings:ImageFolder"];
|
||||||
if (!Directory.Exists(path))
|
if (!Directory.Exists(path))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(path);
|
Directory.CreateDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
extention = System.IO.Path.GetExtension(fileName);
|
|
||||||
filename = familyId + "_" + sdate + extention;
|
|
||||||
string fullpath = System.IO.Path.Combine(path, filename);
|
string fullpath = System.IO.Path.Combine(path, filename);
|
||||||
/*
|
/*
|
||||||
using (var fileStream = new FileStream(fullpath, FileMode.Create))
|
using (var fileStream = new FileStream(fullpath, FileMode.Create))
|
||||||
@@ -520,10 +541,12 @@ public partial class PersonRepository : IPerson
|
|||||||
|
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
using (FileStream fileStream = new FileStream(fullpath, FileMode.Create, FileAccess.Write, FileShare.None))
|
using (FileStream fileStream = new FileStream(fullpath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||||
{
|
{
|
||||||
fileStream.Write(newBytes, 0, newBytes.Length);
|
fileStream.Write(newBytes, 0, newBytes.Length);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
@@ -538,7 +561,7 @@ public partial class PersonRepository : IPerson
|
|||||||
string loginName = "";
|
string loginName = "";
|
||||||
if (httpContext != null)
|
if (httpContext != null)
|
||||||
{
|
{
|
||||||
UserDto? user = (UserDto?)httpContext.Items["User"];
|
UserDto? user = (UserDto?)httpContext.Items["User"];
|
||||||
if (user != null)
|
if (user != null)
|
||||||
loginName = user.FirstName + " " + user.LastName;
|
loginName = user.FirstName + " " + user.LastName;
|
||||||
}
|
}
|
||||||
@@ -571,7 +594,7 @@ public partial class PersonRepository : IPerson
|
|||||||
if (!string.IsNullOrEmpty(container.FileName))
|
if (!string.IsNullOrEmpty(container.FileName))
|
||||||
{
|
{
|
||||||
|
|
||||||
string image = SaveFile(container.FileName, result, container.FormData);
|
string image = await SaveFile(container.FileName, result, container.FormData);
|
||||||
// update the image in table to new
|
// update the image in table to new
|
||||||
model.Image = image;
|
model.Image = image;
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
@@ -587,7 +610,7 @@ public partial class PersonRepository : IPerson
|
|||||||
result = item.Id;
|
result = item.Id;
|
||||||
if (!string.IsNullOrEmpty(container.FileName))
|
if (!string.IsNullOrEmpty(container.FileName))
|
||||||
{
|
{
|
||||||
string image = SaveFile(container.FileName, result, container.FormData);
|
string image = await SaveFile(container.FileName, result, container.FormData);
|
||||||
// update the image in table to new
|
// update the image in table to new
|
||||||
model1.Image = image;
|
model1.Image = image;
|
||||||
}
|
}
|
||||||
@@ -714,17 +737,37 @@ public partial class PersonRepository : IPerson
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> LoadPersonImage(string filename)
|
private async Task<string> LoadPersonImage_old(string filename)
|
||||||
{
|
{
|
||||||
string result = "";
|
string result = "";
|
||||||
|
|
||||||
DownloadFileCriteria criteria = new() { FileName = filename };
|
DownloadFileCriteria criteria = new() { FileName = filename };
|
||||||
var resultModel = await _importPersonRepository.DownloadFile(criteria);
|
var resultModel = await _importPersonRepository.DownloadFile(criteria);
|
||||||
if (!string.IsNullOrEmpty((resultModel.Data)))
|
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(resultModel.Data))
|
||||||
result = "data:image/png;base64," + resultModel.Data;
|
result = "data:image/png;base64," + resultModel.Data;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<string> LoadPersonImage(int personId, int photoType, string filename)
|
||||||
|
{
|
||||||
|
string result = "";
|
||||||
|
|
||||||
|
// DownloadFileCriteria criteria = new() { FileName = filename };
|
||||||
|
|
||||||
|
var resultModel = await _personPhoto.DownloadPersonPhotoPerson(personId, photoType , filename);
|
||||||
|
if (resultModel.StatusCode > 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
string base64String = Convert.ToBase64String(resultModel.Data.Content);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(base64String))
|
||||||
|
result = "data:image/png;base64," + base64String;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public ResultModel<int> DeleteUploadFile(DeleteFileCriteria criteria)
|
public ResultModel<int> DeleteUploadFile(DeleteFileCriteria criteria)
|
||||||
{
|
{
|
||||||
int result = -1;
|
int result = -1;
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ public class Seed
|
|||||||
var conn = _context.Database.GetDbConnection();
|
var conn = _context.Database.GetDbConnection();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
conn.Open();
|
conn.Open();
|
||||||
var command = conn.CreateCommand();
|
var command = conn.CreateCommand();
|
||||||
command.CommandText = sptext;
|
command.CommandText = sptext;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
|
||||||
"AppSettings": {
|
"AppSettings": {
|
||||||
"Secret": "Nepean Blue Mountain Super Secret SIGN AND VERIFY JWT TOKENS, BEARER TOKEN USE WHEN CALLING THIS API.",
|
"Secret": "Super Secret SIGN AND VERIFY JWT TOKENS, BEARER TOKEN USE WHEN CALLING THIS API.",
|
||||||
"SQLConnectionString": "host=localhost;port=5432;database=FamilyTreeDB;username=postgres;password=Positive~1;",
|
"iSQLConnectionString_i": "host=localhost;port=5432;database=familytreedb;username=postgres;password=Positive~1;",
|
||||||
"SQLConnectionString_vm": "host=192.168.1.240;port=5432;database=FamilyTreeDB;username=postgres;password=Positive~1;",
|
"SQLConnectionString": "host=127.0.0.1;port=5432;database=familytreedb;username=postgres;password=Positive~1;",
|
||||||
|
|
||||||
"ImageFolder": "c:\\temp\\Family",
|
"ImageFolder": "/temp/Family",
|
||||||
"ImportFolder": "c:\\temp"
|
"ImportFolder": "/temp"
|
||||||
|
|
||||||
},
|
},
|
||||||
"Logging": {
|
"Logging": {
|
||||||
@@ -17,11 +17,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"Kestrel_not_use": {
|
|
||||||
|
"Kestrel": {
|
||||||
"Endpoints": {
|
"Endpoints": {
|
||||||
"Http": {
|
"Http": {
|
||||||
"Url": "http://*:5015"
|
"Url": "http://localhost:5016"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=ASP.NET Core Web App running on Ubuntu
|
Description=ASP.NET Core Web App running on arch linux
|
||||||
[Service]
|
[Service]
|
||||||
WorkingDirectory=/var/www/familytree/api
|
WorkingDirectory=/var/www/familytree/api
|
||||||
ExecStart=/usr/bin/dotnet /var/www/familytree/api/FamilyTreeAPI.dll
|
ExecStart=/usr/bin/dotnet /var/www/familytree/api/FamilyTreeAPI.dll
|
||||||
Restart=always
|
Restart=always
|
||||||
# Restart service after 10 seconds if the dotnet service crashes:
|
# Restart service after 20 seconds if the dotnet service crashes:
|
||||||
RestartSec=10
|
RestartSec=20
|
||||||
KillSignal=SIGINT
|
KillSignal=SIGINT
|
||||||
SyslogIdentifier=dotnet-web-familytree-api
|
SyslogIdentifier=dotnet-web-familytree-api
|
||||||
# This user should exist on the server and have ownership of the deployment directory
|
# This user should exist on the server and have ownership of the deployment directory
|
||||||
User=www-data
|
#User=www-data this is other ubuntu
|
||||||
|
#arch linux has user http
|
||||||
|
User=http
|
||||||
Environment=ASPNETCORE_ENVIRONMENT=Production
|
Environment=ASPNETCORE_ENVIRONMENT=Production
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
#make sure in nginx.conf has include module.d/*.conf inside http block one.
|
#make sure in nginx.conf has include module.d/*.conf inside http block one.
|
||||||
server {
|
server {
|
||||||
listen 80; #make nginx out side listen 82;
|
listen 80; #make nginx out side listen 82;
|
||||||
location / {
|
location /familytreeapi/ {
|
||||||
proxy_pass http://127.0.0.1:5000;
|
#proxy_pass http://127.0.0.1:5015;
|
||||||
|
proxy_pass http://192.168.1.219:5015/;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection keep-alive;
|
proxy_set_header Connection keep-alive;
|
||||||
@@ -13,20 +14,29 @@
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
return 301 /familytreeui/; #if same one redirect to /familytreeui/
|
||||||
|
}
|
||||||
|
|
||||||
|
location /familytreeui {
|
||||||
|
return 301 /familytreeui/; #if same one redirect to /familytreeui/
|
||||||
|
}
|
||||||
|
|
||||||
location /familytreeui/ {
|
location /familytreeui/ {
|
||||||
root /var/www/familytree; #path must exist like /var/www/familytree/familytreeui and /var/www/familytree/api folder.
|
#root /var/www/familytree/; #path is real must exist like /var/www/familytree/familytreeui and /var/www/familytree/api folder.
|
||||||
index index.html
|
alias /var/www/familytree/ui/; #location does not to match. but angular index baseurl must same as location.
|
||||||
try_files $uri $uri/ /index.html;
|
#index index.html;
|
||||||
|
try_files $uri $uri/ /familytreeui/index.html /index.html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Optional: Cache static assets for better performance
|
# Optional: Cache static assets for better performance
|
||||||
location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
|
#location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
|
||||||
expires 30d;
|
# expires 30d;
|
||||||
add_header Cache-Control "public";
|
# add_header Cache-Control "public";
|
||||||
}
|
#}
|
||||||
|
|
||||||
error_page 404 /index.html;
|
# error_page 404 /index.html;
|
||||||
|
|
||||||
# put in /etc/nginx/sites-availalble/familytreeapp.conf
|
# put in /etc/nginx/sites-availalble/familytreeapp.conf
|
||||||
# link to enable
|
# link to enable
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
|
||||||
|
user http;
|
||||||
|
worker_processes auto;
|
||||||
|
worker_cpu_affinity auto;
|
||||||
|
|
||||||
|
#error_log logs/error.log;
|
||||||
|
#error_log logs/error.log notice;
|
||||||
|
#error_log logs/error.log info;
|
||||||
|
|
||||||
|
#pid logs/nginx.pid;
|
||||||
|
|
||||||
|
|
||||||
|
# Load all installed modules
|
||||||
|
#include modules.d/*.conf;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
http {
|
||||||
|
charset utf-8;
|
||||||
|
include mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
types_hash_max_size 4096;
|
||||||
|
client_max_body_size 16M;
|
||||||
|
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
# '$status $body_bytes_sent "$http_referer" '
|
||||||
|
# '"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
#access_log logs/access.log main;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
#tcp_nopush on;
|
||||||
|
|
||||||
|
#keepalive_timeout 0;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
#gzip on;
|
||||||
|
include modules.d/*.conf;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 81;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
#access_log logs/host.access.log main;
|
||||||
|
|
||||||
|
#kham comment out first
|
||||||
|
#location / {
|
||||||
|
# root /usr/share/nginx/html;
|
||||||
|
# index index.html index.htm;
|
||||||
|
# }
|
||||||
|
|
||||||
|
#error_page 404 /404.html;
|
||||||
|
|
||||||
|
# redirect server error pages to the static page /50x.html
|
||||||
|
#
|
||||||
|
error_page 500 502 503 504 /50x.html;
|
||||||
|
location = /50x.html {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
|
||||||
|
#
|
||||||
|
#location ~ \.php$ {
|
||||||
|
# proxy_pass http://127.0.0.1;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
|
||||||
|
#
|
||||||
|
#location ~ \.php$ {
|
||||||
|
# root html;
|
||||||
|
# fastcgi_pass 127.0.0.1:9000;
|
||||||
|
# fastcgi_index index.php;
|
||||||
|
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
|
||||||
|
# include fastcgi_params;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# deny access to .htaccess files, if Apache's document root
|
||||||
|
# concurs with nginx's one
|
||||||
|
#
|
||||||
|
#location ~ /\.ht {
|
||||||
|
# deny all;
|
||||||
|
#}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# another virtual host using mix of IP-, name-, and port-based configuration
|
||||||
|
#
|
||||||
|
#server {
|
||||||
|
# listen 8000;
|
||||||
|
# listen somename:8080;
|
||||||
|
# server_name somename alias another.alias;
|
||||||
|
|
||||||
|
# location / {
|
||||||
|
# root html;
|
||||||
|
# index index.html index.htm;
|
||||||
|
# }
|
||||||
|
#}
|
||||||
|
|
||||||
|
|
||||||
|
# HTTPS server
|
||||||
|
#
|
||||||
|
#server {
|
||||||
|
# listen 443 ssl;
|
||||||
|
# server_name localhost;
|
||||||
|
|
||||||
|
# ssl_certificate cert.pem;
|
||||||
|
# ssl_certificate_key cert.key;
|
||||||
|
|
||||||
|
# ssl_session_cache shared:SSL:1m;
|
||||||
|
# ssl_session_timeout 5m;
|
||||||
|
|
||||||
|
# ssl_ciphers HIGH:!aNULL:!MD5;
|
||||||
|
# ssl_prefer_server_ciphers on;
|
||||||
|
|
||||||
|
# location / {
|
||||||
|
# root html;
|
||||||
|
# index index.html index.htm;
|
||||||
|
# }
|
||||||
|
#}
|
||||||
|
|
||||||
|
}
|
||||||
+17
-17
@@ -1,17 +1,17 @@
|
|||||||
# Editor configuration, see https://editorconfig.org
|
# Editor configuration, see https://editorconfig.org
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[*.ts]
|
[*.ts]
|
||||||
quote_type = single
|
quote_type = single
|
||||||
ij_typescript_use_double_quotes = false
|
ij_typescript_use_double_quotes = false
|
||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
max_line_length = off
|
max_line_length = off
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
|
|||||||
+43
-43
@@ -1,43 +1,43 @@
|
|||||||
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||||
|
|
||||||
# Compiled output
|
# Compiled output
|
||||||
/dist
|
/dist
|
||||||
/tmp
|
/tmp
|
||||||
/out-tsc
|
/out-tsc
|
||||||
/bazel-out
|
/bazel-out
|
||||||
|
|
||||||
# Node
|
# Node
|
||||||
/node_modules
|
/node_modules
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
|
||||||
# IDEs and editors
|
# IDEs and editors
|
||||||
.idea/
|
.idea/
|
||||||
.project
|
.project
|
||||||
.classpath
|
.classpath
|
||||||
.c9/
|
.c9/
|
||||||
*.launch
|
*.launch
|
||||||
.settings/
|
.settings/
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
|
|
||||||
# Visual Studio Code
|
# Visual Studio Code
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.vscode/settings.json
|
!.vscode/settings.json
|
||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
.history/*
|
.history/*
|
||||||
|
|
||||||
# Miscellaneous
|
# Miscellaneous
|
||||||
/.angular/cache
|
/.angular/cache
|
||||||
.sass-cache/
|
.sass-cache/
|
||||||
/connect.lock
|
/connect.lock
|
||||||
/coverage
|
/coverage
|
||||||
/libpeerconnection.log
|
/libpeerconnection.log
|
||||||
testem.log
|
testem.log
|
||||||
/typings
|
/typings
|
||||||
__screenshots__/
|
__screenshots__/
|
||||||
|
|
||||||
# System files
|
# System files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|||||||
+4
-4
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"@tailwindcss/postcss": {}
|
"@tailwindcss/postcss": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Vendored
+4
-4
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
||||||
"recommendations": ["angular.ng-template"]
|
"recommendations": ["angular.ng-template"]
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+20
-20
@@ -1,20 +1,20 @@
|
|||||||
{
|
{
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "ng serve",
|
"name": "ng serve",
|
||||||
"type": "chrome",
|
"type": "chrome",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"preLaunchTask": "npm: start",
|
"preLaunchTask": "npm: start",
|
||||||
"url": "http://localhost:4200/"
|
"url": "http://localhost:4200/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ng test",
|
"name": "ng test",
|
||||||
"type": "chrome",
|
"type": "chrome",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"preLaunchTask": "npm: test",
|
"preLaunchTask": "npm: test",
|
||||||
"url": "http://localhost:9876/debug.html"
|
"url": "http://localhost:9876/debug.html"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+42
-42
@@ -1,42 +1,42 @@
|
|||||||
{
|
{
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"type": "npm",
|
"type": "npm",
|
||||||
"script": "start",
|
"script": "start",
|
||||||
"isBackground": true,
|
"isBackground": true,
|
||||||
"problemMatcher": {
|
"problemMatcher": {
|
||||||
"owner": "typescript",
|
"owner": "typescript",
|
||||||
"pattern": "$tsc",
|
"pattern": "$tsc",
|
||||||
"background": {
|
"background": {
|
||||||
"activeOnStart": true,
|
"activeOnStart": true,
|
||||||
"beginsPattern": {
|
"beginsPattern": {
|
||||||
"regexp": "(.*?)"
|
"regexp": "(.*?)"
|
||||||
},
|
},
|
||||||
"endsPattern": {
|
"endsPattern": {
|
||||||
"regexp": "bundle generation complete"
|
"regexp": "bundle generation complete"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "npm",
|
"type": "npm",
|
||||||
"script": "test",
|
"script": "test",
|
||||||
"isBackground": true,
|
"isBackground": true,
|
||||||
"problemMatcher": {
|
"problemMatcher": {
|
||||||
"owner": "typescript",
|
"owner": "typescript",
|
||||||
"pattern": "$tsc",
|
"pattern": "$tsc",
|
||||||
"background": {
|
"background": {
|
||||||
"activeOnStart": true,
|
"activeOnStart": true,
|
||||||
"beginsPattern": {
|
"beginsPattern": {
|
||||||
"regexp": "(.*?)"
|
"regexp": "(.*?)"
|
||||||
},
|
},
|
||||||
"endsPattern": {
|
"endsPattern": {
|
||||||
"regexp": "bundle generation complete"
|
"regexp": "bundle generation complete"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-31
@@ -1,32 +1,32 @@
|
|||||||
FROM node:24.0.0 AS build
|
FROM node:24.0.0 AS build
|
||||||
RUN mkdir -p /app
|
RUN mkdir -p /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY ["./*.json", "./"]
|
COPY ["./*.json", "./"]
|
||||||
|
|
||||||
RUN npm install -g @angular/cli
|
RUN npm install -g @angular/cli
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
# Run command in Virtual directory
|
# Run command in Virtual directory
|
||||||
RUN npm cache clean --force
|
RUN npm cache clean --force
|
||||||
|
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
#RUN ng build --configuration=production
|
#RUN ng build --configuration=production
|
||||||
RUN ng build -c=production
|
RUN ng build -c=production
|
||||||
|
|
||||||
FROM nginx:latest
|
FROM nginx:latest
|
||||||
#### copy nginx conf
|
#### copy nginx conf
|
||||||
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
|
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
#COPY --from=build app/dist/Familytree/browser /usr/share/nginx/html
|
#COPY --from=build app/dist/Familytree/browser /usr/share/nginx/html
|
||||||
#### copy artifact build from the 'build environment' old is not in browser folder
|
#### copy artifact build from the 'build environment' old is not in browser folder
|
||||||
COPY --from=build /app/dist/Familytree/browser /usr/share/nginx/html
|
COPY --from=build /app/dist/Familytree/browser /usr/share/nginx/html
|
||||||
|
|
||||||
#CMD ["nginx", "-g", "daemon off;"]
|
#CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
#docker build -t my_angular_app:latest .
|
#docker build -t my_angular_app:latest .
|
||||||
#docker run --name carval -d -p 4200:80 varlidate_ui
|
#docker run --name carval -d -p 4200:80 varlidate_ui
|
||||||
#npm error code ENOENT
|
#npm error code ENOENT
|
||||||
+59
-59
@@ -1,59 +1,59 @@
|
|||||||
# FamilyTreeUI
|
# FamilyTreeUI
|
||||||
|
|
||||||
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.0.2.
|
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.0.2.
|
||||||
|
|
||||||
## Development server
|
## Development server
|
||||||
|
|
||||||
To start a local development server, run:
|
To start a local development server, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ng serve
|
ng serve
|
||||||
```
|
```
|
||||||
|
|
||||||
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
|
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
|
||||||
|
|
||||||
## Code scaffolding
|
## Code scaffolding
|
||||||
|
|
||||||
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ng generate component component-name
|
ng generate component component-name
|
||||||
```
|
```
|
||||||
|
|
||||||
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ng generate --help
|
ng generate --help
|
||||||
```
|
```
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
To build the project run:
|
To build the project run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ng build
|
ng build
|
||||||
```
|
```
|
||||||
|
|
||||||
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
|
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
|
||||||
|
|
||||||
## Running unit tests
|
## Running unit tests
|
||||||
|
|
||||||
To execute unit tests with the [Vitest](https://vitest.dev/) test runner, use the following command:
|
To execute unit tests with the [Vitest](https://vitest.dev/) test runner, use the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ng test
|
ng test
|
||||||
```
|
```
|
||||||
|
|
||||||
## Running end-to-end tests
|
## Running end-to-end tests
|
||||||
|
|
||||||
For end-to-end (e2e) testing, run:
|
For end-to-end (e2e) testing, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ng e2e
|
ng e2e
|
||||||
```
|
```
|
||||||
|
|
||||||
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
||||||
|
|
||||||
## Additional Resources
|
## Additional Resources
|
||||||
|
|
||||||
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
||||||
|
|||||||
+78
-78
@@ -1,78 +1,78 @@
|
|||||||
{
|
{
|
||||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"cli": {
|
"cli": {
|
||||||
"packageManager": "npm",
|
"packageManager": "npm",
|
||||||
"analytics": false
|
"analytics": false
|
||||||
},
|
},
|
||||||
"newProjectRoot": "projects",
|
"newProjectRoot": "projects",
|
||||||
"projects": {
|
"projects": {
|
||||||
"FamilyTreeUI": {
|
"FamilyTreeUI": {
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"schematics": {},
|
"schematics": {},
|
||||||
"root": "",
|
"root": "",
|
||||||
"sourceRoot": "src",
|
"sourceRoot": "src",
|
||||||
"prefix": "app",
|
"prefix": "app",
|
||||||
"architect": {
|
"architect": {
|
||||||
"build": {
|
"build": {
|
||||||
"builder": "@angular/build:application",
|
"builder": "@angular/build:application",
|
||||||
"options": {
|
"options": {
|
||||||
"allowedCommonJsDependencies": [
|
"allowedCommonJsDependencies": [
|
||||||
"moment", "file-saver", "xlsx"
|
"moment", "file-saver", "xlsx"
|
||||||
],
|
],
|
||||||
"browser": "src/main.ts",
|
"browser": "src/main.ts",
|
||||||
"tsConfig": "tsconfig.app.json",
|
"tsConfig": "tsconfig.app.json",
|
||||||
"assets": [
|
"assets": [
|
||||||
{
|
{
|
||||||
"glob": "**/*",
|
"glob": "**/*",
|
||||||
"input": "public"
|
"input": "public"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"src/styles.css"
|
"src/styles.css"
|
||||||
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
"budgets": [
|
"budgets": [
|
||||||
{
|
{
|
||||||
"type": "initial",
|
"type": "initial",
|
||||||
"maximumWarning": "5MB",
|
"maximumWarning": "5MB",
|
||||||
"maximumError": "6MB"
|
"maximumError": "6MB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "anyComponentStyle",
|
"type": "anyComponentStyle",
|
||||||
"maximumWarning": "4kB",
|
"maximumWarning": "4kB",
|
||||||
"maximumError": "8kB"
|
"maximumError": "8kB"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"outputHashing": "all"
|
"outputHashing": "all"
|
||||||
},
|
},
|
||||||
"development": {
|
"development": {
|
||||||
"optimization": false,
|
"optimization": false,
|
||||||
"extractLicenses": false,
|
"extractLicenses": false,
|
||||||
"sourceMap": true
|
"sourceMap": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultConfiguration": "production"
|
"defaultConfiguration": "production"
|
||||||
},
|
},
|
||||||
"serve": {
|
"serve": {
|
||||||
"builder": "@angular/build:dev-server",
|
"builder": "@angular/build:dev-server",
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
"buildTarget": "FamilyTreeUI:build:production"
|
"buildTarget": "FamilyTreeUI:build:production"
|
||||||
},
|
},
|
||||||
"development": {
|
"development": {
|
||||||
"buildTarget": "FamilyTreeUI:build:development"
|
"buildTarget": "FamilyTreeUI:build:development"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultConfiguration": "development"
|
"defaultConfiguration": "development"
|
||||||
},
|
},
|
||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular/build:unit-test"
|
"builder": "@angular/build:unit-test"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-19
@@ -1,20 +1,20 @@
|
|||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
sendfile on;
|
sendfile on;
|
||||||
default_type application/octet-stream;
|
default_type application/octet-stream;
|
||||||
|
|
||||||
gzip on;
|
gzip on;
|
||||||
gzip_http_version 1.1;
|
gzip_http_version 1.1;
|
||||||
gzip_disable "MSIE [1-6]\.";
|
gzip_disable "MSIE [1-6]\.";
|
||||||
gzip_min_length 256;
|
gzip_min_length 256;
|
||||||
gzip_vary on;
|
gzip_vary on;
|
||||||
gzip_proxied expired no-cache no-store private auth;
|
gzip_proxied expired no-cache no-store private auth;
|
||||||
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
||||||
gzip_comp_level 9;
|
gzip_comp_level 9;
|
||||||
|
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ /index.html =404;
|
try_files $uri $uri/ /index.html =404;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Generated
+3194
-3674
File diff suppressed because it is too large
Load Diff
+19
-19
@@ -23,35 +23,35 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "npm@11.6.4",
|
"packageManager": "npm@11.6.4",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/common": "^21.0.0",
|
"@angular/common": "^22.0.0",
|
||||||
"@angular/compiler": "^21.0.0",
|
"@angular/compiler": "^22.0.0",
|
||||||
"@angular/core": "^21.0.0",
|
"@angular/core": "^22.0.0",
|
||||||
"@angular/forms": "^21.0.0",
|
"@angular/forms": "^22.0.0",
|
||||||
"@angular/platform-browser": "^21.0.0",
|
"@angular/platform-browser": "^22.0.0",
|
||||||
"@angular/router": "^21.0.0",
|
"@angular/router": "^22.0.0",
|
||||||
"@ngrx/effects": "^21.0.1",
|
"@ngrx/effects": "^22.0.0",
|
||||||
"@ngrx/store": "^21.0.1",
|
"@ngrx/store": "^22.0.0",
|
||||||
"@ngrx/store-devtools": "^21.0.1",
|
"@ngrx/store-devtools": "^22.0.0",
|
||||||
"@primeuix/themes": "^2.0.2",
|
"@openng/optimus-ui": "^2.0.2",
|
||||||
"@tailwindcss/postcss": "^4.1.17",
|
"@tailwindcss/postcss": "^4.1.17",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"primeicons": "^7.0.0",
|
|
||||||
"primeng": "^21.0.1",
|
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tailwindcss": "^4.1.17",
|
"tailwindcss": "^4.1.17",
|
||||||
"tailwindcss-primeui": "^0.6.1",
|
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"xlsx": "^0.18.5"
|
"xlsx": "^0.18.5",
|
||||||
|
"@openng/icons": "^1.0.0",
|
||||||
|
"@openng/optimus-ui-themes": "^2.0.2",
|
||||||
|
"@openng/optimus-ui-tailwindcss": "^2.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/build": "^21.2.7",
|
"@angular/build": "^22.0.0",
|
||||||
"@angular/cli": "^21.2.7",
|
"@angular/cli": "^22.0.0",
|
||||||
"@angular/compiler-cli": "^21.0.0",
|
"@angular/compiler-cli": "^22.0.0",
|
||||||
"@types/file-saver": "^2.0.7",
|
"@types/file-saver": "^2.0.7",
|
||||||
"jsdom": "^27.1.0",
|
"jsdom": "^27.1.0",
|
||||||
"typescript": "~5.9.2",
|
"typescript": "~6.0.0",
|
||||||
"vitest": "^4.0.8"
|
"vitest": "^4.0.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"baseUrl1": "http://192.168.8.188:5015",
|
"baseUrl1": "http://192.168.8.188:5015",
|
||||||
"baseUrl": "http://localhost:5016",
|
"baseUrl": "http://localhost:5016",
|
||||||
"baseUrl_docker": "http://localhost:8080",
|
"baseUrl_docker": "http://localhost:8080",
|
||||||
"attachment": "http://localhost/document/family"
|
"attachment": "http://localhost/document/family",
|
||||||
|
"username": "kham.vilaythong@gmail.com",
|
||||||
|
"prefill_ps": "passwor"
|
||||||
}
|
}
|
||||||
+18
-18
@@ -1,19 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
|
||||||
<system.webServer>
|
<system.webServer>
|
||||||
<rewrite>
|
<rewrite>
|
||||||
<rules>
|
<rules>
|
||||||
<rule name="Angular Routes" stopProcessing="true">
|
<rule name="Angular Routes" stopProcessing="true">
|
||||||
<match url=".*" />
|
<match url=".*" />
|
||||||
<conditions logicalGrouping="MatchAll">
|
<conditions logicalGrouping="MatchAll">
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||||
</conditions>
|
</conditions>
|
||||||
<action type="Rewrite" url="./index.html" />
|
<action type="Rewrite" url="./index.html" />
|
||||||
</rule>
|
</rule>
|
||||||
</rules>
|
</rules>
|
||||||
</rewrite>
|
</rewrite>
|
||||||
</system.webServer>
|
</system.webServer>
|
||||||
|
|
||||||
</configuration>
|
</configuration>
|
||||||
+66
-66
@@ -1,67 +1,67 @@
|
|||||||
import { ApplicationConfig, provideBrowserGlobalErrorListeners ,
|
import { ApplicationConfig, provideBrowserGlobalErrorListeners ,
|
||||||
provideAppInitializer} from '@angular/core';
|
provideAppInitializer} from '@angular/core';
|
||||||
import { provideRouter, withComponentInputBinding } from '@angular/router';
|
import { provideRouter, withComponentInputBinding } from '@angular/router';
|
||||||
import { providePrimeNG } from 'primeng/config';
|
import { provideOptimus } from '@openng/optimus-ui/config';
|
||||||
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
||||||
import { ConfirmationService, MessageService } from 'primeng/api';
|
import { ConfirmationService, MessageService } from '@openng/optimus-ui/api';
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
import MyPreset from './mythem';
|
import MyPreset from './mythem';
|
||||||
import { JwtInterceptor, ErrorInterceptor, initializeApp } from './shares';
|
import { JwtInterceptor, ErrorInterceptor, initializeApp } from './shares';
|
||||||
|
|
||||||
import { provideStore } from '@ngrx/store';
|
import { provideStore } from '@ngrx/store';
|
||||||
import { provideStoreDevtools } from '@ngrx/store-devtools';
|
import { provideStoreDevtools } from '@ngrx/store-devtools';
|
||||||
import { isDevMode } from '@angular/core';
|
import { isDevMode } from '@angular/core';
|
||||||
import { provideEffects } from '@ngrx/effects';
|
import { provideEffects } from '@ngrx/effects';
|
||||||
import { staffEffects,staffsReducer } from './state';
|
import { staffEffects,staffsReducer } from './state';
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [
|
providers: [
|
||||||
provideStore({
|
provideStore({
|
||||||
myStaffs: staffsReducer,
|
myStaffs: staffsReducer,
|
||||||
}),
|
}),
|
||||||
provideEffects([staffEffects]),
|
provideEffects([staffEffects]),
|
||||||
provideStoreDevtools({
|
provideStoreDevtools({
|
||||||
maxAge: 30,
|
maxAge: 30,
|
||||||
logOnly: !isDevMode()
|
logOnly: !isDevMode()
|
||||||
}),
|
}),
|
||||||
provideBrowserGlobalErrorListeners(),
|
provideBrowserGlobalErrorListeners(),
|
||||||
MessageService, ConfirmationService,
|
MessageService, ConfirmationService,
|
||||||
provideAppInitializer(initializeApp()),
|
provideAppInitializer(initializeApp()),
|
||||||
provideHttpClient(withInterceptors([JwtInterceptor, ErrorInterceptor])),
|
provideHttpClient(withInterceptors([JwtInterceptor, ErrorInterceptor])),
|
||||||
provideRouter(routes, withComponentInputBinding()),
|
provideRouter(routes, withComponentInputBinding()),
|
||||||
providePrimeNG({
|
provideOptimus({
|
||||||
theme: {
|
theme: {
|
||||||
preset: MyPreset,
|
preset: MyPreset,
|
||||||
options: {
|
options: {
|
||||||
cssLayer: {
|
cssLayer: {
|
||||||
name: 'primeng',
|
name: 'optimus',
|
||||||
order: 'theme, base, primeng'
|
order: 'theme, base, optimus'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
$) ng build --base-href "/familytreeui/" -c production
|
$) ng build --base-href "/familytreeui/" -c production
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
private readonly store = inject(Store);
|
private readonly store = inject(Store);
|
||||||
protected books = this.store.selectSignal(selectBooks);
|
protected books = this.store.selectSignal(selectBooks);
|
||||||
protected onAdd(id: number) {
|
protected onAdd(id: number) {
|
||||||
this.store.dispatch(StaffsActions.addStaff({ id }));
|
this.store.dispatch(StaffsActions.addStaff({ id }));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onRemove(id: number) {
|
protected onRemove(id: number) {
|
||||||
this.store.dispatch(StaffsActions.removeStaff({ id }));
|
this.store.dispatch(StaffsActions.removeStaff({ id }));
|
||||||
}
|
}
|
||||||
on ngOnInit() {
|
on ngOnInit() {
|
||||||
use it normal get from API first
|
use it normal get from API first
|
||||||
and subscribe( (x) => this.store.dispatch(StaffApiAction.LoadStaffList({x})))
|
and subscribe( (x) => this.store.dispatch(StaffApiAction.LoadStaffList({x})))
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
+4
-4
@@ -1,5 +1,5 @@
|
|||||||
<p-toast position="bottom-center" />
|
<p-toast position="bottom-center" />
|
||||||
<app-toolbar> </app-toolbar>
|
<app-toolbar> </app-toolbar>
|
||||||
<router-outlet />
|
<router-outlet />
|
||||||
<p-confirmDialog [style]="{width: '50vw'}"
|
<p-confirmDialog [style]="{width: '50vw'}"
|
||||||
rejectButtonStyleClass="p-button-text"> </p-confirmDialog>
|
rejectButtonStyleClass="p-button-text"> </p-confirmDialog>
|
||||||
+19
-19
@@ -1,19 +1,19 @@
|
|||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
import { Login } from './login';
|
import { Login } from './login';
|
||||||
import { StaffComponent, StaffEditComponent } from './staff';
|
import { StaffComponent, StaffEditComponent } from './staff';
|
||||||
import { AuthGuard } from './route-guard';
|
import { AuthGuard } from './route-guard';
|
||||||
import { FamilyTree, FamilyList} from './person';
|
import { FamilyTree, FamilyList} from './person';
|
||||||
import { ImportCom } from './import.com/import.com';
|
import { ImportCom } from './import.com/import.com';
|
||||||
import { ImageDisplayComponent } from './pickperson/image.display';
|
import { ImageDisplayComponent } from './pickperson/image.display';
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{ path: '', redirectTo: 'login', pathMatch: 'full' },
|
{ path: '', redirectTo: 'login', pathMatch: 'full' },
|
||||||
// { path: 'approval', component: ApprovalComponent,canActivate: [AuthGuard], data: { roleAllowed: '1,2,3' }},},
|
// { path: 'approval', component: ApprovalComponent,canActivate: [AuthGuard], data: { roleAllowed: '1,2,3' }},},
|
||||||
{ path: 'login', component: Login},
|
{ path: 'login', component: Login},
|
||||||
{ path: 'staff', component: StaffComponent},
|
{ path: 'staff', component: StaffComponent},
|
||||||
{ path: 'person', component: FamilyList},
|
{ path: 'person', component: FamilyList},
|
||||||
{ path: 'imagedisplay/:id', component: ImageDisplayComponent},
|
{ path: 'imagedisplay/:id', component: ImageDisplayComponent},
|
||||||
{ path: 'import', component: ImportCom},
|
{ path: 'import', component: ImportCom},
|
||||||
{ path: 'familytree', component: FamilyTree},
|
{ path: 'familytree', component: FamilyTree},
|
||||||
{ path: 'staff/:id', component: StaffEditComponent},
|
{ path: 'staff/:id', component: StaffEditComponent},
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
+15
-15
@@ -1,15 +1,15 @@
|
|||||||
|
|
||||||
import { Component, signal } from '@angular/core';
|
import { Component, signal } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
import { ToolbarComponent } from './toolbar/toolbar.component';
|
import { ToolbarComponent } from './toolbar/toolbar.component';
|
||||||
import { ToastModule } from 'primeng/toast';
|
import { ToastModule } from '@openng/optimus-ui/toast';
|
||||||
import { ConfirmDialogModule } from 'primeng/confirmdialog';
|
import { ConfirmDialogModule } from '@openng/optimus-ui/confirmdialog';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
imports: [RouterOutlet,ToastModule,ToolbarComponent,ConfirmDialogModule],
|
imports: [RouterOutlet,ToastModule,ToolbarComponent,ConfirmDialogModule],
|
||||||
templateUrl: './app.html',
|
templateUrl: './app.html',
|
||||||
styleUrl: './app.css'
|
styleUrl: './app.css'
|
||||||
})
|
})
|
||||||
export class App {
|
export class App {
|
||||||
protected readonly title = signal('FamilyTree');
|
protected readonly title = signal('FamilyTree');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
<div class="card gap-2">
|
<div class="card gap-2">
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<input type="file" class="file-input hidden" (change)="onFileSelected($event)" #fileUpload multiple>
|
<input type="file" class="file-input hidden" (change)="onFileSelected($event)" #fileUpload multiple>
|
||||||
<div class="file-upload">
|
<div class="file-upload">
|
||||||
<label>{{fileName || "Photo upload:"}}</label>
|
<label>{{fileName || "Photo upload:"}}</label>
|
||||||
<button pButton type="button" icon="pi pi-paperclip"
|
<button pButton type="button" icon="pi pi-paperclip"
|
||||||
class="p-button-rounded p-button-text p-button-raised ml-2" pTooltip="attach file"
|
class="p-button-rounded p-button-text p-button-raised ml-2" pTooltip="attach file"
|
||||||
(click)="fileUpload.click()"></button>
|
(click)="fileUpload.click()"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-end justify-end mt-4">
|
<div class="flex items-end justify-end mt-4">
|
||||||
@if (files)
|
@if (files)
|
||||||
{
|
{
|
||||||
<button pButton pRipple type="button" icon="pi pi-upload" label="OK" class="p-button-sm mr-2"
|
<button pButton pRipple type="button" icon="pi pi-upload" label="OK" class="p-button-sm mr-2"
|
||||||
(click)="upload($event)"></button>
|
(click)="upload($event)"></button>
|
||||||
}
|
}
|
||||||
<button pButton pRipple type="button" icon="pi pi-times" label="Cancel" class="p-button-sm"
|
<button pButton pRipple type="button" icon="pi pi-times" label="Cancel" class="p-button-sm"
|
||||||
(click)="cancel($event)"></button>
|
(click)="cancel($event)"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+178
-178
@@ -1,178 +1,178 @@
|
|||||||
import { ChangeDetectorRef, Component, inject, Inject, OnDestroy, OnInit, signal } from '@angular/core';
|
import { ChangeDetectorRef, Component, inject, Inject, OnDestroy, OnInit, signal } from '@angular/core';
|
||||||
import { DynamicDialogModule, DynamicDialogRef ,DynamicDialogConfig} from 'primeng/dynamicdialog';
|
import { DynamicDialogModule, DynamicDialogRef ,DynamicDialogConfig} from '@openng/optimus-ui/dynamicdialog';
|
||||||
|
|
||||||
import { LookupEdit } from '../models';
|
import { LookupEdit } from '../models';
|
||||||
import { UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
|
import { UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { Subject, Subscription } from 'rxjs';
|
import { Subject, Subscription } from 'rxjs';
|
||||||
import { ConfirmationService, MessageService } from 'primeng/api';
|
import { ConfirmationService, MessageService } from '@openng/optimus-ui/api';
|
||||||
import { LookupService } from '../shares';
|
import { LookupService } from '../shares';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { CheckboxModule } from 'primeng/checkbox';
|
import { CheckboxModule } from '@openng/optimus-ui/checkbox';
|
||||||
import { InputTextModule } from 'primeng/inputtext';
|
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||||
import { ButtonModule } from 'primeng/button';
|
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'add-photo',
|
selector: 'add-photo',
|
||||||
imports: [CommonModule, ReactiveFormsModule,
|
imports: [CommonModule, ReactiveFormsModule,
|
||||||
ButtonModule, InputTextModule,
|
ButtonModule, InputTextModule,
|
||||||
DynamicDialogModule, CheckboxModule],
|
DynamicDialogModule, CheckboxModule],
|
||||||
templateUrl: './add.photo.html',
|
templateUrl: './add.photo.html',
|
||||||
styleUrls: ['./add.photo.css'],
|
styleUrls: ['./add.photo.css'],
|
||||||
providers: [ConfirmationService]
|
providers: [ConfirmationService]
|
||||||
})
|
})
|
||||||
export class AddPhoto implements OnInit, OnDestroy {
|
export class AddPhoto implements OnInit, OnDestroy {
|
||||||
isChange = true; // disable use false//true for not disable. make sure it true is disable button.
|
isChange = true; // disable use false//true for not disable. make sure it true is disable button.
|
||||||
selType = "";
|
selType = "";
|
||||||
_error = "";
|
_error = "";
|
||||||
downloadFile = signal(false);
|
downloadFile = signal(false);
|
||||||
files: File[] = [];
|
files: File[] = [];
|
||||||
fileName = "";
|
fileName = "";
|
||||||
disabled: boolean = true;
|
disabled: boolean = true;
|
||||||
subChanged$ = new Subject<boolean>();
|
subChanged$ = new Subject<boolean>();
|
||||||
private formBuilder = inject(UntypedFormBuilder);
|
private formBuilder = inject(UntypedFormBuilder);
|
||||||
private cdr = inject(ChangeDetectorRef);
|
private cdr = inject(ChangeDetectorRef);
|
||||||
private subscription: Subscription = new Subscription();
|
private subscription: Subscription = new Subscription();
|
||||||
lookupForm = this.formBuilder.group({
|
lookupForm = this.formBuilder.group({
|
||||||
id: [0], //Validators.required
|
id: [0], //Validators.required
|
||||||
description: ['', [Validators.required, Validators.maxLength(50)]],
|
description: ['', [Validators.required, Validators.maxLength(50)]],
|
||||||
codeId: ['', [Validators.required]],
|
codeId: ['', [Validators.required]],
|
||||||
parentId: [0],
|
parentId: [0],
|
||||||
|
|
||||||
active: [false], //Validators.required
|
active: [false], //Validators.required
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|
||||||
private lookupService: LookupService,
|
private lookupService: LookupService,
|
||||||
private messageService: MessageService,
|
private messageService: MessageService,
|
||||||
private confirmationService: ConfirmationService,
|
private confirmationService: ConfirmationService,
|
||||||
public ref: DynamicDialogRef, public config: DynamicDialogConfig) { }
|
public ref: DynamicDialogRef, public config: DynamicDialogConfig) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
const id = this.config.data.id;
|
const id = this.config.data.id;
|
||||||
this.selType = this.config.data.type;
|
this.selType = this.config.data.type;
|
||||||
const maxcodeId = this.config.data.maxCodeId;
|
const maxcodeId = this.config.data.maxCodeId;
|
||||||
if (id > 0) {
|
if (id > 0) {
|
||||||
this.lookupService.loadLookupById(id, this.selType).subscribe({
|
this.lookupService.loadLookupById(id, this.selType).subscribe({
|
||||||
next: x => {
|
next: x => {
|
||||||
this.assignValue(x.data);
|
this.assignValue(x.data);
|
||||||
this.cdr.markForCheck();
|
this.cdr.markForCheck();
|
||||||
this.subscription.add(this.lookupForm.valueChanges.subscribe(x => this.isChange = false));
|
this.subscription.add(this.lookupForm.valueChanges.subscribe(x => this.isChange = false));
|
||||||
this.subscription.add(this.subChanged$.subscribe(x => this.isChange = x));
|
this.subscription.add(this.subChanged$.subscribe(x => this.isChange = x));
|
||||||
|
|
||||||
},
|
},
|
||||||
error: e => {
|
error: e => {
|
||||||
console.error("error", e);
|
console.error("error", e);
|
||||||
this.messageService.add({ severity: 'error', summary: 'Error on load cleaner ', detail: e.message });
|
this.messageService.add({ severity: 'error', summary: 'Error on load cleaner ', detail: e.message });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//new photo
|
//new photo
|
||||||
const ward:LookupEdit = {
|
const ward:LookupEdit = {
|
||||||
id, description: '', codeId: maxcodeId, type: this.selType, active: true,
|
id, description: '', codeId: maxcodeId, type: this.selType, active: true,
|
||||||
|
|
||||||
};
|
};
|
||||||
this.assignValue(ward);
|
this.assignValue(ward);
|
||||||
this.subscription.add(this.lookupForm.valueChanges.subscribe(x => this.isChange = false));
|
this.subscription.add(this.lookupForm.valueChanges.subscribe(x => this.isChange = false));
|
||||||
this.subscription.add(this.subChanged$.subscribe(x => this.isChange = x));
|
this.subscription.add(this.subChanged$.subscribe(x => this.isChange = x));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getClassForRequire(prev: string, name: string) {
|
getClassForRequire(prev: string, name: string) {
|
||||||
const notok = !this.lookupForm.controls[name].valid &&
|
const notok = !this.lookupForm.controls[name].valid &&
|
||||||
this.lookupForm.controls[name].touched;
|
this.lookupForm.controls[name].touched;
|
||||||
let str = prev;
|
let str = prev;
|
||||||
if (notok)
|
if (notok)
|
||||||
str += " ng-invalid ng-dirty";
|
str += " ng-invalid ng-dirty";
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
get isFieldsChange() {
|
get isFieldsChange() {
|
||||||
const chan = this.isChange || !this.lookupForm.valid; // this disable so need true valid = true not
|
const chan = this.isChange || !this.lookupForm.valid; // this disable so need true valid = true not
|
||||||
//console.log(this.msg + 'is fields change', chan);
|
//console.log(this.msg + 'is fields change', chan);
|
||||||
return chan;
|
return chan;
|
||||||
}
|
}
|
||||||
|
|
||||||
assignValue(item: LookupEdit): void {
|
assignValue(item: LookupEdit): void {
|
||||||
this.lookupForm.patchValue({
|
this.lookupForm.patchValue({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
codeId: item.codeId,
|
codeId: item.codeId,
|
||||||
description: item.description,
|
description: item.description,
|
||||||
active: item.active,
|
active: item.active,
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
// disable use false//true for not disable.
|
// disable use false//true for not disable.
|
||||||
this.subChanged$.next(true);
|
this.subChanged$.next(true);
|
||||||
}
|
}
|
||||||
validate(item: LookupEdit): boolean {
|
validate(item: LookupEdit): boolean {
|
||||||
let result = true;
|
let result = true;
|
||||||
if (item.description!.trim() == "") {
|
if (item.description!.trim() == "") {
|
||||||
this._error = "Description is empty or blank";
|
this._error = "Description is empty or blank";
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
deleteFile() : void {
|
deleteFile() : void {
|
||||||
//const filename = this.requestForm.value.attachmentFile;
|
//const filename = this.requestForm.value.attachmentFile;
|
||||||
// const data = { filename };
|
// const data = { filename };
|
||||||
this.fileName ="";
|
this.fileName ="";
|
||||||
//this.requestForm.patchValue({ attachmentFile: "" });
|
//this.requestForm.patchValue({ attachmentFile: "" });
|
||||||
/*
|
/*
|
||||||
const delete$ = this.tradePersonService.deleteUploadFile(data);
|
const delete$ = this.tradePersonService.deleteUploadFile(data);
|
||||||
this.subscription.add(delete$.subscribe(
|
this.subscription.add(delete$.subscribe(
|
||||||
{
|
{
|
||||||
next: x => {
|
next: x => {
|
||||||
if (x.statusCode == 1) {
|
if (x.statusCode == 1) {
|
||||||
{
|
{
|
||||||
this.requestForm.patchValue({ attachmentFile: "" });
|
this.requestForm.patchValue({ attachmentFile: "" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.messageService.add({ severity: 'error', summary: 'Error delete upload file', detail: 'Fail to delete upload file: ' + x.message });
|
this.messageService.add({ severity: 'error', summary: 'Error delete upload file', detail: 'Fail to delete upload file: ' + x.message });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: e => {
|
error: e => {
|
||||||
this.messageService.add({ severity: 'error', summary: 'Error delete upload file', detail: 'Fail to delete upload file: ' + e });
|
this.messageService.add({ severity: 'error', summary: 'Error delete upload file', detail: 'Fail to delete upload file: ' + e });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
onFileSelected(event: any) {
|
onFileSelected(event: any) {
|
||||||
|
|
||||||
let i =0;
|
let i =0;
|
||||||
for (i = 0; i < event.target.files.length; i++)
|
for (i = 0; i < event.target.files.length; i++)
|
||||||
{
|
{
|
||||||
const file: File = event.target.files[i];
|
const file: File = event.target.files[i];
|
||||||
this.files.push(file);
|
this.files.push(file);
|
||||||
if (this.fileName != "")
|
if (this.fileName != "")
|
||||||
this.fileName = this.fileName + "," + file.name;
|
this.fileName = this.fileName + "," + file.name;
|
||||||
else
|
else
|
||||||
this.fileName = file.name;
|
this.fileName = file.name;
|
||||||
|
|
||||||
this.subChanged$.next(false);
|
this.subChanged$.next(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
upload(e: Event): void {
|
upload(e: Event): void {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (this.files.length > 0)
|
if (this.files.length > 0)
|
||||||
{
|
{
|
||||||
this.ref.close(this.files);
|
this.ref.close(this.files);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.messageService.add({severity: 'error', summary: 'No File to upload file', detail: 'select file first then upload file'});
|
this.messageService.add({severity: 'error', summary: 'No File to upload file', detail: 'select file first then upload file'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel(e: Event): void {
|
cancel(e: Event): void {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.ref.close(null);
|
this.ref.close(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.subscription.unsubscribe();
|
this.subscription.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
export * from './photolist';
|
export * from './photolist';
|
||||||
export * from './add.photo';
|
export * from './add.photo';
|
||||||
@@ -1,49 +1,50 @@
|
|||||||
<div class="shadow-xl rounded-md p-2">
|
<div class="shadow-xl rounded-md p-2">
|
||||||
<div class="flex fex-row justify-between mb-2">
|
<div class="flex fex-row justify-between mb-2">
|
||||||
<p> please click save at the end</p>
|
<p> please click save at the end</p>
|
||||||
<div class="flex items-end self-end">
|
<div class="flex items-end self-end">
|
||||||
<button pButton pRipple type="button" icon="pi pi-file" label="Attach Photo" class="p-button-sm"
|
<button pButton pRipple type="button" icon="pi pi-file" label="Attach Photo" class="p-button-sm"
|
||||||
(click)="newSupportDoc($event)"></button>
|
(click)="newSupportDoc($event)"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<p-table [value]="FileList" sortMode="multiple" class="p-datatable-sm"
|
<p-table [value]="FileList" sortMode="multiple" class="p-datatable-sm"
|
||||||
[loading]="loading">
|
[loading]="loading">
|
||||||
|
|
||||||
<ng-template pTemplate="header">
|
<ng-template pTemplate="header">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Id</th>
|
<th>Id</th>
|
||||||
<th pSortableColumn="description">Description<p-sortIcon field="description"></p-sortIcon>
|
<th pSortableColumn="description">Description<p-sortIcon field="description"></p-sortIcon>
|
||||||
</th>
|
</th>
|
||||||
|
<th>Photo Type</th>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template pTemplate="body" let-item>
|
<ng-template pTemplate="body" let-item>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{item.id}}</td>
|
<td>{{item.id}}</td>
|
||||||
<td >{{item.photo}}</td>
|
<td >{{item.photo}}</td>
|
||||||
<td>
|
<td>{{item.photoType}}</td>
|
||||||
|
<td>
|
||||||
<button pButton type="button" icon="pi pi-times"
|
|
||||||
pTooltip="Delete" class="p-button-rounded text-red-500 p-button-text p-button-raised mr-2"
|
<button pButton type="button" icon="pi pi-times"
|
||||||
(click)="remove(item.id)"></button>
|
pTooltip="Delete" class="p-button-rounded text-red-500 p-button-text p-button-raised mr-2"
|
||||||
|
(click)="remove(item.id)"></button>
|
||||||
@if (item.id > 0) {
|
|
||||||
<button pButton type="button" icon="pi pi-file"
|
@if (item.id > 0) {
|
||||||
pTooltip="Download Photo"
|
<button pButton type="button" icon="pi pi-file"
|
||||||
class="p-button-rounded p-button-text p-button-raised"
|
pTooltip="Download Photo"
|
||||||
(click)="downloadAttachment(item.id)"></button>
|
class="p-button-rounded p-button-text p-button-raised"
|
||||||
}
|
(click)="downloadAttachment(item.id)"></button>
|
||||||
</td>
|
}
|
||||||
</tr>
|
</td>
|
||||||
</ng-template>
|
</tr>
|
||||||
</p-table>
|
</ng-template>
|
||||||
|
</p-table>
|
||||||
<div class="flex items-end justify-end mt-4">
|
|
||||||
<button pButton pRipple type="button" icon="pi pi-times" label="Close" class="p-button-sm"
|
<div class="flex items-end justify-end mt-4">
|
||||||
(click)="onClose($event)"></button>
|
<button pButton pRipple type="button" icon="pi pi-times" label="Close" class="p-button-sm"
|
||||||
</div>
|
(click)="onClose($event)"></button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
+183
-183
@@ -1,183 +1,183 @@
|
|||||||
//import { Component, OnInit, OnDestroy } from '@angular/core';
|
//import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { Component, OnInit, OnDestroy, inject, ChangeDetectorRef, signal, output } from '@angular/core';
|
import { Component, OnInit, OnDestroy, inject, ChangeDetectorRef, signal, output } from '@angular/core';
|
||||||
import { catchError, EMPTY, finalize, Subscription } from 'rxjs';
|
import { catchError, EMPTY, finalize, Subscription } from 'rxjs';
|
||||||
import { CommonUtilities, HttpUtility, LookupService } from '../shares';
|
import { CommonUtilities, HttpUtility, LookupService } from '../shares';
|
||||||
import { DialogService ,DynamicDialogConfig,DynamicDialogModule, DynamicDialogRef} from 'primeng/dynamicdialog';
|
import { DialogService ,DynamicDialogConfig,DynamicDialogModule, DynamicDialogRef} from '@openng/optimus-ui/dynamicdialog';
|
||||||
import { ConfirmationService, MessageService } from 'primeng/api';
|
import { ConfirmationService, MessageService } from '@openng/optimus-ui/api';
|
||||||
import { AddPhoto } from './add.photo';
|
import { AddPhoto } from './add.photo';
|
||||||
import { PersonPhotoDto } from '../models';
|
import { PersonPhotoDto } from '../models';
|
||||||
|
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { TableModule } from 'primeng/table';
|
import { TableModule } from '@openng/optimus-ui/table';
|
||||||
import { ButtonModule } from 'primeng/button';
|
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||||
import { TooltipModule } from 'primeng/tooltip';
|
import { TooltipModule } from '@openng/optimus-ui/tooltip';
|
||||||
import { AuthenticationService } from '../user-services';
|
import { AuthenticationService } from '../user-services';
|
||||||
import { HttpResponse } from '@angular/common/http';
|
import { HttpResponse } from '@angular/common/http';
|
||||||
import { PersonService } from '../person';
|
import { PersonService } from '../person';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'photo-list',
|
selector: 'photo-list',
|
||||||
imports: [CommonModule, FormsModule, DynamicDialogModule,TooltipModule,
|
imports: [CommonModule, FormsModule, DynamicDialogModule,TooltipModule,
|
||||||
ButtonModule, TableModule],
|
ButtonModule, TableModule],
|
||||||
templateUrl: './photolist.html',
|
templateUrl: './photolist.html',
|
||||||
styleUrls: ['./photolist.css'],
|
styleUrls: ['./photolist.css'],
|
||||||
providers: [DialogService]
|
providers: [DialogService]
|
||||||
})
|
})
|
||||||
export class PhotoList implements OnInit, OnDestroy {
|
export class PhotoList implements OnInit, OnDestroy {
|
||||||
FileList: PersonPhotoDto[] =[]
|
FileList: PersonPhotoDto[] =[]
|
||||||
loading = false;
|
loading = false;
|
||||||
_id = -1;
|
_id = -1;
|
||||||
deletePersonPhoto: number[] = [];
|
deletePersonPhoto: number[] = [];
|
||||||
private authenticationService = inject(AuthenticationService);
|
private authenticationService = inject(AuthenticationService);
|
||||||
private cdr = inject(ChangeDetectorRef);
|
private cdr = inject(ChangeDetectorRef);
|
||||||
private confirmationService = inject(ConfirmationService);
|
private confirmationService = inject(ConfirmationService);
|
||||||
private messageService = inject(MessageService);
|
private messageService = inject(MessageService);
|
||||||
private subscription: Subscription = new Subscription();
|
private subscription: Subscription = new Subscription();
|
||||||
downloadFile = signal(false);
|
downloadFile = signal(false);
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpUtility,
|
private http: HttpUtility,
|
||||||
private personService: PersonService,
|
private personService: PersonService,
|
||||||
|
|
||||||
public ref: DynamicDialogRef, public config: DynamicDialogConfig,
|
public ref: DynamicDialogRef, public config: DynamicDialogConfig,
|
||||||
public dialogService: DialogService
|
public dialogService: DialogService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
const id = this.config.data.id;
|
const id = this.config.data.id;
|
||||||
const olist = this.config.data.personPhotos;
|
const olist = this.config.data.personPhotos;
|
||||||
if (olist && olist.length > 0)
|
if (olist && olist.length > 0)
|
||||||
{
|
{
|
||||||
this.FileList = olist;
|
this.FileList = olist;
|
||||||
this.assignFileId(olist);
|
this.assignFileId(olist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assignFileId(files: any[]): void {
|
assignFileId(files: any[]): void {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let id = -1;
|
let id = -1;
|
||||||
let mx = 1;
|
let mx = 1;
|
||||||
for (i = 0; i < files.length; i++)
|
for (i = 0; i < files.length; i++)
|
||||||
{
|
{
|
||||||
id = files[i].id;
|
id = files[i].id;
|
||||||
if (id < mx)
|
if (id < mx)
|
||||||
{
|
{
|
||||||
mx = id;
|
mx = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._id = -1 * mx;
|
this._id = -1 * mx;
|
||||||
}
|
}
|
||||||
downloadAttachment(id: number): void {
|
downloadAttachment(id: number): void {
|
||||||
//GetReportFile
|
//GetReportFile
|
||||||
|
|
||||||
let typeofCall = "personId_" + id.toString();
|
let typeofCall = "personPhotoId_" + id.toString();
|
||||||
|
|
||||||
let criteria:any ={id, fileName:''};
|
let criteria: any = { id };
|
||||||
this.downloadFile.set(false);
|
this.downloadFile.set(false);
|
||||||
this.http.getFileResponse("api/FileUpload/downloadPersonPhoto", criteria).pipe(
|
this.http.getFileResponse("api/FileUpload/DownloadPersonPhotoById", criteria).pipe(
|
||||||
catchError(err => {
|
catchError(err => {
|
||||||
console.error(err.message);
|
console.error(err.message);
|
||||||
return EMPTY;
|
return EMPTY;
|
||||||
}),
|
}),
|
||||||
finalize(() => {
|
finalize(() => {
|
||||||
// this.toastr.success("download completed ok to view now");
|
// this.toastr.success("download completed ok to view now");
|
||||||
this.downloadFile.set(false);
|
this.downloadFile.set(false);
|
||||||
|
|
||||||
})).subscribe((response: HttpResponse<Blob>) => {
|
})).subscribe((response: HttpResponse<Blob>) => {
|
||||||
if (response) {
|
if (response) {
|
||||||
console.log("the download report response", response);
|
console.log("the download report response", response);
|
||||||
CommonUtilities.downloadFile(response, typeofCall);
|
CommonUtilities.downloadFile(response, typeofCall);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onClose(event: Event): void {
|
onClose(event: Event): void {
|
||||||
const nlist = this.FileList.filter( x => x.id < 1);
|
const nlist = this.FileList.filter( x => x.id < 1);
|
||||||
this.ref.close({list: nlist, deleteIds: this.deletePersonPhoto});
|
this.ref.close({list: nlist, deleteIds: this.deletePersonPhoto});
|
||||||
}
|
}
|
||||||
newSupportDoc(event: Event): void {
|
newSupportDoc(event: Event): void {
|
||||||
this.showEdit(this._id--);
|
this.showEdit(this._id--);
|
||||||
}
|
}
|
||||||
remove(id: number): void {
|
remove(id: number): void {
|
||||||
this.confirmationService.confirm({
|
this.confirmationService.confirm({
|
||||||
|
|
||||||
message: 'Do you want to delete this record?',
|
message: 'Do you want to delete this record?',
|
||||||
header: 'Confirmation Delete',
|
header: 'Confirmation Delete',
|
||||||
icon: 'pi pi-info-circle',
|
icon: 'pi pi-info-circle',
|
||||||
rejectLabel: 'Cancel',
|
rejectLabel: 'Cancel',
|
||||||
rejectButtonProps: {
|
rejectButtonProps: {
|
||||||
label: 'Cancel',
|
label: 'Cancel',
|
||||||
severity: 'secondary',
|
severity: 'secondary',
|
||||||
outlined: true,
|
outlined: true,
|
||||||
},
|
},
|
||||||
acceptButtonProps: {
|
acceptButtonProps: {
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
severity: 'danger',
|
severity: 'danger',
|
||||||
},
|
},
|
||||||
|
|
||||||
accept: () => {
|
accept: () => {
|
||||||
this.doRemove(id);
|
this.doRemove(id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
doRemove(id: number): void {
|
doRemove(id: number): void {
|
||||||
if (id < 0)
|
if (id < 0)
|
||||||
{
|
{
|
||||||
const nlist = this.FileList.filter(x => x.id != id);
|
const nlist = this.FileList.filter(x => x.id != id);
|
||||||
this.FileList = [...nlist];
|
this.FileList = [...nlist];
|
||||||
this.cdr.markForCheck();
|
this.cdr.markForCheck();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const deletepersonPhoto$ = this.personService.deletePersonPhotoFile(id);
|
const deletepersonPhoto$ = this.personService.deletePersonPhotoFileById(id);
|
||||||
this.subscription.add(deletepersonPhoto$.subscribe(
|
this.subscription.add(deletepersonPhoto$.subscribe(
|
||||||
{
|
{
|
||||||
next: x => {
|
next: x => {
|
||||||
if (x.statusCode == 1)
|
if (x.statusCode == 1)
|
||||||
{
|
{
|
||||||
const nlist = this.FileList.filter(x => x.id != id);
|
const nlist = this.FileList.filter(x => x.id != id);
|
||||||
this.FileList = [...nlist];
|
this.FileList = [...nlist];
|
||||||
this.deletePersonPhoto.push(id);
|
this.deletePersonPhoto.push(id);
|
||||||
this.cdr.markForCheck();
|
this.cdr.markForCheck();
|
||||||
this.messageService.add({severity:'success', summary: 'delete person photo', detail: "person photo Id " + id });
|
this.messageService.add({severity:'success', summary: 'delete person photo', detail: "person photo Id " + id });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error:e => console.error("error in client delete person photo", e)
|
error:e => console.error("error in client delete person photo", e)
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
showEdit(id: number) {
|
showEdit(id: number) {
|
||||||
const ref = this.dialogService.open(AddPhoto, {
|
const ref = this.dialogService.open(AddPhoto, {
|
||||||
data: {
|
data: {
|
||||||
id,
|
id,
|
||||||
},
|
},
|
||||||
header: 'Add File',
|
header: 'Add File',
|
||||||
width: '70%',
|
width: '70%',
|
||||||
maximizable: true,
|
maximizable: true,
|
||||||
draggable: true
|
draggable: true
|
||||||
});
|
});
|
||||||
if (ref)
|
if (ref)
|
||||||
{
|
{
|
||||||
ref.onClose.subscribe((list: File[]) => {
|
ref.onClose.subscribe((list: File[]) => {
|
||||||
if (list) {
|
if (list) {
|
||||||
//console.log("after close ward edit", item);
|
//console.log("after close ward edit", item);
|
||||||
this.messageService.add({ severity: 'success', summary: 'Attact File', detail: list.length.toString() });
|
this.messageService.add({ severity: 'success', summary: 'Attact File', detail: list.length.toString() });
|
||||||
let it = id;
|
let it = id;
|
||||||
for (let i = 0; i < list.length; i++)
|
for (let i = 0; i < list.length; i++)
|
||||||
{
|
{
|
||||||
const item = list[i];
|
const item = list[i];
|
||||||
this.FileList.push({id: it--, photo: item.name, photoType:'', file: item});
|
this.FileList.push({id: it--, photo: item.name, photoType:'', file: item});
|
||||||
}
|
}
|
||||||
this.cdr.markForCheck();
|
this.cdr.markForCheck();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.subscription.unsubscribe();
|
this.subscription.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<div>
|
<div>
|
||||||
<label class="flex mb-2"> Import Excel File</label>
|
<label class="flex mb-2"> Import Excel File</label>
|
||||||
<p-fileupload #fu mode="basic" chooseLabel="Choose"
|
<p-fileupload #fu mode="basic" chooseLabel="Choose"
|
||||||
chooseIcon="pi pi-upload" name="file"
|
chooseIcon="pi pi-upload" name="file"
|
||||||
url='{{baseUrl}}'
|
url='{{baseUrl}}'
|
||||||
maxFileSize="10000000000" (onUpload)="onUpload($event)" />
|
maxFileSize="10000000000" (onUpload)="onUpload($event)" />
|
||||||
<p-button styleClass="mt-4" label="Upload" (onClick)="fu.upload()" severity="primary" />
|
<p-button styleClass="mt-4" label="Upload" (onClick)="fu.upload()" severity="primary" />
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
import { Component, inject, OnInit } from '@angular/core';
|
import { Component, inject, OnInit } from '@angular/core';
|
||||||
import { ButtonModule } from 'primeng/button';
|
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||||
import { FileUploadEvent, FileUploadModule } from 'primeng/fileupload';
|
import { FileUploadEvent, FileUploadModule } from '@openng/optimus-ui/fileupload';
|
||||||
import { MessageService } from 'primeng/api';
|
import { MessageService } from '@openng/optimus-ui/api';
|
||||||
import { FileUpload } from 'primeng/fileupload';
|
import { FileUpload } from '@openng/optimus-ui/fileupload';
|
||||||
import { ToastModule } from 'primeng/toast';
|
import { ToastModule } from '@openng/optimus-ui/toast';
|
||||||
import { AppSettingService } from '../shares';
|
import { AppSettingService } from '../shares';
|
||||||
/*
|
/*
|
||||||
interface UploadEvent {
|
interface UploadEvent {
|
||||||
originalEvent: Event;
|
originalEvent: Event;
|
||||||
files: File[];
|
files: File[];
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-import.com',
|
selector: 'app-import.com',
|
||||||
imports: [FileUploadModule, ButtonModule,ToastModule,FileUpload],
|
imports: [FileUploadModule, ButtonModule,ToastModule,FileUpload],
|
||||||
templateUrl: './import.com.html',
|
templateUrl: './import.com.html',
|
||||||
styleUrl: './import.com.css'
|
styleUrl: './import.com.css'
|
||||||
})
|
})
|
||||||
export class ImportCom implements OnInit {
|
export class ImportCom implements OnInit {
|
||||||
uploadedFiles: any[] = [];
|
uploadedFiles: any[] = [];
|
||||||
baseUrl = "";
|
baseUrl = "";
|
||||||
private appSetting = inject(AppSettingService);
|
private appSetting = inject(AppSettingService);
|
||||||
constructor(private messageService: MessageService) {}
|
constructor(private messageService: MessageService) {}
|
||||||
ngOnInit(): void
|
ngOnInit(): void
|
||||||
{
|
{
|
||||||
const cbaseUrl = this.appSetting.appSetting.baseUrl;
|
const cbaseUrl = this.appSetting.appSetting.baseUrl;
|
||||||
//http://localhost:5015/api/FileUpload/UploadFile"
|
//http://localhost:5015/api/FileUpload/UploadFile"
|
||||||
this.baseUrl = cbaseUrl + "/api/FileUpload/UploadFile";
|
this.baseUrl = cbaseUrl + "/api/FileUpload/UploadFile";
|
||||||
}
|
}
|
||||||
onUpload(event:FileUploadEvent) {
|
onUpload(event:FileUploadEvent) {
|
||||||
for(let file of event.files) {
|
for(let file of event.files) {
|
||||||
this.uploadedFiles.push(file);
|
this.uploadedFiles.push(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.messageService.add({severity: 'info', summary: 'File Uploaded', detail: ''});
|
this.messageService.add({severity: 'info', summary: 'File Uploaded', detail: ''});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<form runat="server">
|
<form runat="server">
|
||||||
<input accept="image/*" type='file' id="imgInp" />
|
<input accept="image/*" type='file' id="imgInp" />
|
||||||
<img id="blah" src="#" alt="your image" />
|
<img id="blah" src="#" alt="your image" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
imgInp.onchange = evt => {
|
imgInp.onchange = evt => {
|
||||||
const [file] = imgInp.files
|
const [file] = imgInp.files
|
||||||
if (file) {
|
if (file) {
|
||||||
blah.src = URL.createObjectURL(file)
|
blah.src = URL.createObjectURL(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
export * from './login';
|
export * from './login';
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
.btnloginRigh {
|
.btnloginRigh {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction:reverse;
|
flex-direction:reverse;
|
||||||
justify-content:flex-end;
|
justify-content:flex-end;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.myerror {
|
.myerror {
|
||||||
background-color: red;
|
background-color: red;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
+44
-44
@@ -1,45 +1,45 @@
|
|||||||
<div class="flex justify-center items-center h-full">
|
<div class="flex justify-center items-center h-full">
|
||||||
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()" style="max-width: 600px;min-width: 300px;">
|
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()" style="max-width: 600px;min-width: 300px;">
|
||||||
<p-card>
|
<p-card>
|
||||||
<div>
|
<div>
|
||||||
<img class="border-round" style="width:100%;height:100px;" alt="Logo" src="images/application_image_login.png">
|
<img class="border-round" style="width:100%;height:100px;" alt="Logo" src="images/application_image_login.png">
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<label for="email" class="w-full">Email<strong class="validateStar">*</strong></label>
|
<label for="email" class="w-full">Email<strong class="validateStar">*</strong></label>
|
||||||
<input type="text" pInputText formControlName="username" name="email"
|
<input type="text" pInputText formControlName="username" name="email"
|
||||||
[ngClass]="{ 'is-invalid': submitted && f.username.errors }" class="p-inputtext-sm inputfield">
|
[ngClass]="{ 'is-invalid': submitted && f.username.errors }" class="p-inputtext-sm inputfield">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<label for="ppassword" class="w-full">Password <strong class="validateStar">*</strong></label>
|
<label for="ppassword" class="w-full">Password <strong class="validateStar">*</strong></label>
|
||||||
<input type="password" formControlName="password" name="ppassword" pInputText
|
<input type="password" formControlName="password" name="ppassword" pInputText
|
||||||
[ngClass]="{ 'is-invalid': submitted && f.password.errors }" class="p-inputtext-sm inputfield">
|
[ngClass]="{ 'is-invalid': submitted && f.password.errors }" class="p-inputtext-sm inputfield">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!--p-footer -->
|
<!--p-footer -->
|
||||||
<div class="btnloginRigh">
|
<div class="btnloginRigh">
|
||||||
<div class="mt-4 pt-2">
|
<div class="mt-4 pt-2">
|
||||||
<button pButton type="submit" label="Login" class="p-button-sm" [disabled]="isFieldsChange"
|
<button pButton type="submit" label="Login" class="p-button-sm" [disabled]="isFieldsChange"
|
||||||
[loading]="loading"></button>
|
[loading]="loading"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--/p-footer-->
|
<!--/p-footer-->
|
||||||
|
|
||||||
</p-card>
|
</p-card>
|
||||||
<div class="myerror">{{error}}</div>
|
<div class="myerror">{{error}}</div>
|
||||||
<div style="padding-top: 10px;"></div>
|
<div style="padding-top: 10px;"></div>
|
||||||
<!--div
|
<!--div
|
||||||
style="text-align: center;display:inline-block;border-radius: var(--border-radius) !important;background-color:#e1e1e1; color:#222;font-size:13px;width:100%; margin-left:5px;margin-right: 5px;">
|
style="text-align: center;display:inline-block;border-radius: var(--border-radius) !important;background-color:#e1e1e1; color:#222;font-size:13px;width:100%; margin-left:5px;margin-right: 5px;">
|
||||||
<p >
|
<p >
|
||||||
For management access to this application please email
|
For management access to this application please email
|
||||||
</p>
|
</p>
|
||||||
<a href="mailto:NBMLHD-fleetteamreceipt@health.nsw.gov.au">NBMLHD-fleetteamreceipt@health.nsw.gov.au
|
<a href="mailto:NBMLHD-fleetteamreceipt@health.nsw.gov.au">NBMLHD-fleetteamreceipt@health.nsw.gov.au
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div-->
|
</div-->
|
||||||
<!--pre> {{loginForm.value|json}} </pre-->
|
<!--pre> {{loginForm.value|json}} </pre-->
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
+137
-135
@@ -1,135 +1,137 @@
|
|||||||
import { Component, OnDestroy, OnInit, inject } from '@angular/core';
|
import { Component, OnDestroy, OnInit, inject } from '@angular/core';
|
||||||
import { Router, ActivatedRoute, RouterModule } from '@angular/router';
|
import { Router, ActivatedRoute, RouterModule } from '@angular/router';
|
||||||
import { FormBuilder, Validators, FormGroup } from '@angular/forms';
|
import { FormBuilder, Validators, FormGroup } from '@angular/forms';
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from 'rxjs/operators';
|
||||||
|
|
||||||
import { AuthenticationService } from '../user-services';
|
import { AuthenticationService } from '../user-services';
|
||||||
|
|
||||||
import { ConfirmationService } from 'primeng/api';
|
import { ConfirmationService } from '@openng/optimus-ui/api';
|
||||||
import { Subject, Subscription } from 'rxjs';
|
import { Subject, Subscription } from 'rxjs';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { CardModule } from 'primeng/card';
|
import { CardModule } from '@openng/optimus-ui/card';
|
||||||
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
||||||
import { ButtonModule } from 'primeng/button';
|
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||||
import { InputTextModule } from 'primeng/inputtext';
|
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||||
|
|
||||||
import { Utils } from '../shares';
|
import { AppSettingService, Utils } from '../shares';
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './login.html',
|
templateUrl: './login.html',
|
||||||
styleUrl: './login.css',
|
styleUrl: './login.css',
|
||||||
selector: 'login',
|
selector: 'login',
|
||||||
imports: [FormsModule, ReactiveFormsModule, ButtonModule, InputTextModule,
|
imports: [FormsModule, ReactiveFormsModule, ButtonModule, InputTextModule,
|
||||||
RouterModule, CommonModule, CardModule],
|
RouterModule, CommonModule, CardModule],
|
||||||
|
|
||||||
})
|
})
|
||||||
export class Login implements OnInit, OnDestroy {
|
export class Login implements OnInit, OnDestroy {
|
||||||
loginForm: FormGroup;
|
loginForm: FormGroup;
|
||||||
confirmationService = inject(ConfirmationService);
|
confirmationService = inject(ConfirmationService);
|
||||||
route = inject(ActivatedRoute);
|
route = inject(ActivatedRoute);
|
||||||
router = inject(Router);
|
router = inject(Router);
|
||||||
authenticationService = inject(AuthenticationService);
|
authenticationService = inject(AuthenticationService);
|
||||||
formBuilder = inject(FormBuilder);
|
formBuilder = inject(FormBuilder);
|
||||||
loading = false;
|
private appSetting =inject(AppSettingService);
|
||||||
homeUrl = "/person";
|
loading = false;
|
||||||
submitted = false;
|
homeUrl = "/person";
|
||||||
isChange = true; // disable use false//true for not disable. make sure it true is disable button.
|
submitted = false;
|
||||||
subChanged$ = new Subject<boolean>();
|
isChange = true; // disable use false//true for not disable. make sure it true is disable button.
|
||||||
// get return url from route parameters or default to '/'
|
subChanged$ = new Subject<boolean>();
|
||||||
returnUrl = this.route.snapshot.queryParams['returnUrl'] || this.homeUrl;
|
// get return url from route parameters or default to '/'
|
||||||
error = '';
|
returnUrl = this.route.snapshot.queryParams['returnUrl'] || this.homeUrl;
|
||||||
private subscription: Subscription = new Subscription();
|
error = '';
|
||||||
|
private subscription: Subscription = new Subscription();
|
||||||
constructor() {
|
|
||||||
|
constructor() {
|
||||||
this.loginForm = this.formBuilder.group({
|
const default_us = this.appSetting.appSetting.username;
|
||||||
username: ['kham.vilaythong@gmail.com', Validators.required],
|
const pass = this.appSetting.appSetting.prefill_ps;
|
||||||
password: ['password', Validators.required],
|
this.loginForm = this.formBuilder.group({
|
||||||
|
username: [default_us, Validators.required],
|
||||||
});
|
password: [pass, Validators.required],
|
||||||
}
|
|
||||||
|
});
|
||||||
ngOnInit() {
|
}
|
||||||
// reset login status
|
|
||||||
this.loading = false;
|
ngOnInit() {
|
||||||
this.subscription.add(this.loginForm.valueChanges.subscribe((x: any) => this.isChange = false));
|
// reset login status
|
||||||
this.subscription.add(this.subChanged$.subscribe(x => this.isChange = x));
|
this.loading = false;
|
||||||
|
this.subscription.add(this.loginForm.valueChanges.subscribe((x: any) => this.isChange = false));
|
||||||
}
|
this.subscription.add(this.subChanged$.subscribe(x => this.isChange = x));
|
||||||
|
|
||||||
updateData($event: Event) {
|
}
|
||||||
console.log("onChange click", $event);
|
|
||||||
}
|
updateData($event: Event) {
|
||||||
|
console.log("onChange click", $event);
|
||||||
// convenience getter for easy access to form fields
|
}
|
||||||
get f() { return this.loginForm.value; }
|
|
||||||
get isFieldsChange() {
|
// convenience getter for easy access to form fields
|
||||||
const chan = this.isChange || !this.loginForm.valid; // this disable so need true valid = true not
|
get f() { return this.loginForm.value; }
|
||||||
//console.log(this.msg + 'is fields change', chan);
|
get isFieldsChange() {
|
||||||
return chan;
|
const chan = this.isChange || !this.loginForm.valid; // this disable so need true valid = true not
|
||||||
}
|
//console.log(this.msg + 'is fields change', chan);
|
||||||
onSubmit() {
|
return chan;
|
||||||
|
}
|
||||||
//this.playAudio();
|
onSubmit() {
|
||||||
|
|
||||||
// stop here if form is invalid
|
//this.playAudio();
|
||||||
if (this.loginForm.invalid) {
|
|
||||||
return;
|
// stop here if form is invalid
|
||||||
}
|
if (this.loginForm.invalid) {
|
||||||
const fvalue = this.loginForm.value;
|
return;
|
||||||
this.loading = true;
|
}
|
||||||
this.error = "";
|
const fvalue = this.loginForm.value;
|
||||||
let username = "";
|
this.loading = true;
|
||||||
let password = "";
|
this.error = "";
|
||||||
if (fvalue.username != null)
|
let username = "";
|
||||||
username = fvalue.username;
|
let password = "";
|
||||||
if (fvalue.password != null)
|
if (fvalue.username != null)
|
||||||
password = fvalue.password;
|
username = fvalue.username;
|
||||||
this.authenticationService.login(username, password)
|
if (fvalue.password != null)
|
||||||
.pipe(first())
|
password = fvalue.password;
|
||||||
.subscribe({
|
this.authenticationService.login(username, password)
|
||||||
next: (x: any) => {
|
.pipe(first())
|
||||||
this.loading = false;
|
.subscribe({
|
||||||
console.log("login result ", x.data, this.returnUrl);
|
next: (x: any) => {
|
||||||
if (x.statusCode == 1) {
|
this.loading = false;
|
||||||
// if (x.data.role == 1) {
|
console.log("login result ", x.data, this.returnUrl);
|
||||||
// this.homeService.reportDate = Utils.getLastMonth();
|
if (x.statusCode == 1) {
|
||||||
// this.router.navigate(['/addkpi/' + x.data.id + '/' + x.data.measureId], { queryParams: { returnUrl: '/login' } });
|
// if (x.data.role == 1) {
|
||||||
|
// this.homeService.reportDate = Utils.getLastMonth();
|
||||||
// }
|
// this.router.navigate(['/addkpi/' + x.data.id + '/' + x.data.measureId], { queryParams: { returnUrl: '/login' } });
|
||||||
// else if (x.data.role == 3) {
|
|
||||||
// this.homeService.reportDate = Utils.getLastMonth();
|
// }
|
||||||
// this.router.navigate(['/approval/' + x.data.id], { queryParams: { returnUrl: '/login' } });
|
// else if (x.data.role == 3) {
|
||||||
|
// this.homeService.reportDate = Utils.getLastMonth();
|
||||||
//}
|
// this.router.navigate(['/approval/' + x.data.id], { queryParams: { returnUrl: '/login' } });
|
||||||
// else
|
|
||||||
this.router.navigate([this.homeUrl]);
|
//}
|
||||||
}
|
// else
|
||||||
else {
|
this.router.navigate([this.homeUrl]);
|
||||||
this.loginForm.patchValue({ password: '' });
|
}
|
||||||
// alert("Invalid Username or Password. Please try again.");
|
else {
|
||||||
console.error("error in login", x);
|
this.loginForm.patchValue({ password: '' });
|
||||||
this.confirmationService.confirm({
|
// alert("Invalid Username or Password. Please try again.");
|
||||||
message: 'Error in Login: Invalid username or password. May be your password is expired',
|
console.error("error in login", x);
|
||||||
header: 'Error Login',
|
this.confirmationService.confirm({
|
||||||
icon: 'pi pi-info-circle',
|
message: 'Error in Login: Invalid username or password. May be your password is expired',
|
||||||
rejectVisible: false,
|
header: 'Error Login',
|
||||||
acceptLabel: 'OK',
|
icon: 'pi pi-info-circle',
|
||||||
|
rejectVisible: false,
|
||||||
});
|
acceptLabel: 'OK',
|
||||||
}
|
|
||||||
},
|
});
|
||||||
error: er => {
|
}
|
||||||
console.log("error in login", er);
|
},
|
||||||
this.error = er.message;
|
error: er => {
|
||||||
this.loading = false;
|
console.log("error in login", er);
|
||||||
}
|
this.error = er.message;
|
||||||
});
|
this.loading = false;
|
||||||
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
}
|
||||||
this.subscription.unsubscribe();
|
|
||||||
this.loading = false;
|
ngOnDestroy(): void {
|
||||||
}
|
this.subscription.unsubscribe();
|
||||||
|
this.loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export interface Code {
|
export interface Code {
|
||||||
id:number;
|
id:number;
|
||||||
name:string;
|
name:string;
|
||||||
status?:string;
|
status?:string;
|
||||||
active?:boolean;
|
active?:boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
export enum ConfigureUrl
|
export enum ConfigureUrl
|
||||||
{
|
{
|
||||||
//baseUrl = "http://localhost:61744",
|
//baseUrl = "http://localhost:61744",
|
||||||
loginApiUrl = "api/Users/Login",
|
loginApiUrl = "api/Users/Login",
|
||||||
searchStaffUrl = "api/Users/SearchADStaff",
|
searchStaffUrl = "api/Users/SearchADStaff",
|
||||||
staffUrl = "api/Staff",
|
staffUrl = "api/Staff",
|
||||||
personUrl = "api/Person",
|
personUrl = "api/Person",
|
||||||
staffWorkUrl = "api/StaffWork",
|
staffWorkUrl = "api/StaffWork",
|
||||||
jobUrl ="api/Job",
|
jobUrl ="api/Job",
|
||||||
clientUrl ="api/Client",
|
clientUrl ="api/Client",
|
||||||
relationShipUrl ="api/RelationShip",
|
relationShipUrl ="api/RelationShip",
|
||||||
logoutUrl ="api/Users/Logout",
|
logoutUrl ="api/Users/Logout",
|
||||||
adminUserUrl = "api/Staff",
|
adminUserUrl = "api/Staff",
|
||||||
lookupUrl = "api/Lookup",
|
lookupUrl = "api/Lookup",
|
||||||
FileUploadUrl = "api/FileUpload",
|
FileUploadUrl = "api/FileUpload",
|
||||||
|
|
||||||
}
|
}
|
||||||
+40
-37
@@ -1,37 +1,40 @@
|
|||||||
export const MIMEType = {
|
export const MIMEType = {
|
||||||
png: 'image/png',
|
png: 'image/png',
|
||||||
jpg: 'image/jpg',
|
jpg: 'image/jpg',
|
||||||
jpeg: 'image/jpeg',
|
jpeg: 'image/jpeg',
|
||||||
gif: 'image/gif',
|
gif: 'image/gif',
|
||||||
txt: 'text/plain',
|
txt: 'text/plain',
|
||||||
pdf: 'application/pdf'
|
pdf: 'application/pdf'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//for status of object 0 no change, 1 changed , -1 is deleted.
|
//for status of object 0 no change, 1 changed , -1 is deleted.
|
||||||
export enum mState {
|
export enum mState {
|
||||||
Delete = -1,
|
Delete = -1,
|
||||||
NoChange = 0,
|
NoChange = 0,
|
||||||
Modified = 1,
|
Modified = 1,
|
||||||
New =2,
|
New =2,
|
||||||
};
|
};
|
||||||
|
export enum enumPhoto {
|
||||||
export enum userRole {
|
Profile = 1,
|
||||||
Normal = 1,
|
Other = 2
|
||||||
Admin = 2,
|
}
|
||||||
ServiceManager =3,
|
export enum userRole {
|
||||||
Accounting = 4,
|
Normal = 1,
|
||||||
WorkShop = 5,
|
Admin = 2,
|
||||||
|
ServiceManager =3,
|
||||||
};
|
Accounting = 4,
|
||||||
|
WorkShop = 5,
|
||||||
export enum enumReqStatus {
|
|
||||||
Canel = -1,
|
};
|
||||||
Decline = -2,
|
|
||||||
NewRequest = 0,
|
export enum enumReqStatus {
|
||||||
Allocate = 1,
|
Canel = -1,
|
||||||
Arrival = 2,
|
Decline = -2,
|
||||||
Completed = 3,
|
NewRequest = 0,
|
||||||
OnHold = 4,
|
Allocate = 1,
|
||||||
OffHold = 5
|
Arrival = 2,
|
||||||
};
|
Completed = 3,
|
||||||
|
OnHold = 4,
|
||||||
|
OffHold = 5
|
||||||
|
};
|
||||||
|
|||||||
+10
-10
@@ -1,11 +1,11 @@
|
|||||||
export * from './code';
|
export * from './code';
|
||||||
export * from './configureUrl';
|
export * from './configureUrl';
|
||||||
export * from './user';
|
export * from './user';
|
||||||
export * from './resultmodel';
|
export * from './resultmodel';
|
||||||
export * from './enum';
|
export * from './enum';
|
||||||
export * from './lookup';
|
export * from './lookup';
|
||||||
export * from './staff';
|
export * from './staff';
|
||||||
export * from './person';
|
export * from './person';
|
||||||
export * from './job';
|
export * from './job';
|
||||||
export * from './relationship';
|
export * from './relationship';
|
||||||
export * from './personphotodto';
|
export * from './personphotodto';
|
||||||
+12
-12
@@ -1,12 +1,12 @@
|
|||||||
|
|
||||||
export interface JobSearch {
|
export interface JobSearch {
|
||||||
code:string;
|
code:string;
|
||||||
description:string;
|
description:string;
|
||||||
}
|
}
|
||||||
export interface Job {
|
export interface Job {
|
||||||
id:number;
|
id:number;
|
||||||
code:string|null|undefined;
|
code:string|null|undefined;
|
||||||
description:string |null|undefined;
|
description:string |null|undefined;
|
||||||
active:boolean |null|undefined;
|
active:boolean |null|undefined;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-15
@@ -1,16 +1,16 @@
|
|||||||
// using for priority and infectionType
|
// using for priority and infectionType
|
||||||
export interface Lookup {
|
export interface Lookup {
|
||||||
id:number;
|
id:number;
|
||||||
codeId:string;
|
codeId:string;
|
||||||
description:string;
|
description:string;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LookupEdit {
|
export interface LookupEdit {
|
||||||
id:number;
|
id:number;
|
||||||
codeId:string;
|
codeId:string;
|
||||||
description:string;
|
description:string;
|
||||||
active:boolean;
|
active:boolean;
|
||||||
type:string;
|
type:string;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
export interface MyDetail{
|
export interface MyDetail{
|
||||||
id:number,
|
id:number,
|
||||||
login:string,
|
login:string,
|
||||||
firstname:string,
|
firstname:string,
|
||||||
surname:string,
|
surname:string,
|
||||||
jobTitle:string,
|
jobTitle:string,
|
||||||
}
|
}
|
||||||
+37
-37
@@ -1,37 +1,37 @@
|
|||||||
import { PersonPhotoDto } from "./personphotodto";
|
import { PersonPhotoDto } from "./personphotodto";
|
||||||
import { RelationShip } from "./relationship";
|
import { RelationShip } from "./relationship";
|
||||||
|
|
||||||
export interface FamilySearch {
|
export interface FamilySearch {
|
||||||
email:string|null;
|
email:string|null;
|
||||||
phone:string |null;
|
phone:string |null;
|
||||||
clientname:string |null;
|
clientname:string |null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Person {
|
export interface Person {
|
||||||
|
|
||||||
id: number;
|
id: number;
|
||||||
title?:string| null| undefined;
|
title?:string| null| undefined;
|
||||||
firstName: string | null|undefined;
|
firstName: string | null|undefined;
|
||||||
lastName: string | null|undefined;
|
lastName: string | null|undefined;
|
||||||
email: string | null|undefined;
|
email: string | null|undefined;
|
||||||
phone: string | null|undefined;
|
phone: string | null|undefined;
|
||||||
address?: string | null|undefined;
|
address?: string | null|undefined;
|
||||||
alive: boolean | null|undefined;
|
alive: boolean | null|undefined;
|
||||||
dob? : string | null|undefined;
|
dob? : string | null|undefined;
|
||||||
fatherId?: number| null|undefined;
|
fatherId?: number| null|undefined;
|
||||||
motherId?: number| null|undefined;
|
motherId?: number| null|undefined;
|
||||||
image?: string|null|undefined;
|
image?: string|null|undefined;
|
||||||
sex?: string|null|undefined;
|
sex?: string|null|undefined;
|
||||||
fatherName?:string |null;
|
fatherName?:string |null;
|
||||||
motherName?:string |null;
|
motherName?:string |null;
|
||||||
relationShips?: RelationShip[];
|
relationShips?: RelationShip[];
|
||||||
personPhotos?: PersonPhotoDto[];
|
personPhotos?: PersonPhotoDto[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PersonContainer
|
export interface PersonContainer
|
||||||
{
|
{
|
||||||
person: Person;
|
person: Person;
|
||||||
formData?:FormData;
|
formData?:FormData;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export interface PersonPhotoDto {
|
export interface PersonPhotoDto {
|
||||||
id: number;
|
id: number;
|
||||||
photo:string|null | undefined;
|
photo:string|null | undefined;
|
||||||
photoType:string |null | undefined;
|
photoType:string |null | undefined;
|
||||||
file: File | null | undefined;
|
file: File | null | undefined;
|
||||||
}
|
}
|
||||||
@@ -1,27 +1,27 @@
|
|||||||
import { mState } from "./enum";
|
import { mState } from "./enum";
|
||||||
|
|
||||||
export interface RelationShip {
|
export interface RelationShip {
|
||||||
id: number;
|
id: number;
|
||||||
relatePersonId: number;
|
relatePersonId: number;
|
||||||
personId: number;
|
personId: number;
|
||||||
state: mState;
|
state: mState;
|
||||||
}
|
}
|
||||||
//relationship id this relatePersonId person has relation with other person
|
//relationship id this relatePersonId person has relation with other person
|
||||||
// also other person has also has relation with you. look in two way
|
// also other person has also has relation with you. look in two way
|
||||||
// person id = 1 has to relation id = 90
|
// person id = 1 has to relation id = 90
|
||||||
// that means when you edit person 90 their relation ship also be there.
|
// that means when you edit person 90 their relation ship also be there.
|
||||||
// so personid = 1 and relation id = 90 we need to show other way around.
|
// so personid = 1 and relation id = 90 we need to show other way around.
|
||||||
//example first name = Smith has partner Jennifer
|
//example first name = Smith has partner Jennifer
|
||||||
// when we edit Jennifer it should show Smith as her partner too.
|
// when we edit Jennifer it should show Smith as her partner too.
|
||||||
|
|
||||||
export interface RelationShipView {
|
export interface RelationShipView {
|
||||||
id: number;
|
id: number;
|
||||||
relatePersonId:number;
|
relatePersonId:number;
|
||||||
personId : number;
|
personId : number;
|
||||||
pfirstName: string |null |undefined;
|
pfirstName: string |null |undefined;
|
||||||
plastName: string |null |undefined;
|
plastName: string |null |undefined;
|
||||||
sex:string |null |undefined;
|
sex:string |null |undefined;
|
||||||
state: mState;
|
state: mState;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
export interface ResultModel<T> {
|
export interface ResultModel<T> {
|
||||||
data: T;
|
data: T;
|
||||||
message: string;
|
message: string;
|
||||||
statusCode:number;
|
statusCode:number;
|
||||||
}
|
}
|
||||||
+39
-39
@@ -1,39 +1,39 @@
|
|||||||
export interface StaffView {
|
export interface StaffView {
|
||||||
id:number,
|
id:number,
|
||||||
email:string,
|
email:string,
|
||||||
firstname:string,
|
firstname:string,
|
||||||
lastname:string,
|
lastname:string,
|
||||||
active:boolean,
|
active:boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResetPassword{
|
export interface ResetPassword{
|
||||||
id:number;
|
id:number;
|
||||||
password:string;
|
password:string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Staff {
|
export interface Staff {
|
||||||
id:number,
|
id:number,
|
||||||
email:string,
|
email:string,
|
||||||
firstname:string,
|
firstname:string,
|
||||||
lastname:string,
|
lastname:string,
|
||||||
phone:string,
|
phone:string,
|
||||||
type:number;
|
type:number;
|
||||||
active:boolean;
|
active:boolean;
|
||||||
roleType: number;
|
roleType: number;
|
||||||
password?:string,
|
password?:string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StaffSearch {
|
export interface StaffSearch {
|
||||||
email:string;
|
email:string;
|
||||||
firstName:string;
|
firstName:string;
|
||||||
lastName:string;
|
lastName:string;
|
||||||
}
|
}
|
||||||
|
|
||||||
//this use for new user only.
|
//this use for new user only.
|
||||||
export interface AdminUserNew {
|
export interface AdminUserNew {
|
||||||
loginId:number;
|
loginId:number;
|
||||||
user: Staff;// first get userid from this table and
|
user: Staff;// first get userid from this table and
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+36
-36
@@ -1,36 +1,36 @@
|
|||||||
export class User {
|
export class User {
|
||||||
id: number = 0;
|
id: number = 0;
|
||||||
username: string = '';
|
username: string = '';
|
||||||
role: number = -1;
|
role: number = -1;
|
||||||
firstName: string = '';
|
firstName: string = '';
|
||||||
lastName: string = '';
|
lastName: string = '';
|
||||||
email:string = '';
|
email:string = '';
|
||||||
token:string ='';
|
token:string ='';
|
||||||
position: string ='';
|
position: string ='';
|
||||||
department: string = '';
|
department: string = '';
|
||||||
managerEmail:string ='';
|
managerEmail:string ='';
|
||||||
phone:string='';
|
phone:string='';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserAD
|
export interface UserAD
|
||||||
{
|
{
|
||||||
id: number,
|
id: number,
|
||||||
firstName: string,
|
firstName: string,
|
||||||
lastName: string,
|
lastName: string,
|
||||||
email: string,
|
email: string,
|
||||||
username: string,
|
username: string,
|
||||||
department: string,
|
department: string,
|
||||||
position: string,
|
position: string,
|
||||||
role: number,
|
role: number,
|
||||||
phone:string,
|
phone:string,
|
||||||
managerEmail:string
|
managerEmail:string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SecAccessLevel {
|
export class SecAccessLevel {
|
||||||
accessName:string='';
|
accessName:string='';
|
||||||
request:number=0;
|
request:number=0;
|
||||||
report:number=0;
|
report:number=0;
|
||||||
admin:number=0;
|
admin:number=0;
|
||||||
allocation:number=0;
|
allocation:number=0;
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-38
@@ -1,51 +1,41 @@
|
|||||||
|
|
||||||
|
|
||||||
//mypreset.ts
|
//mypreset.ts
|
||||||
import { definePreset } from '@primeuix/themes';
|
import { definePreset } from '@openng/optimus-ui-themes';
|
||||||
import Aura from '@primeuix/themes/aura';
|
import Aura from '@openng/optimus-ui-themes/aura';
|
||||||
import { primitive } from '@primeuix/themes/aura/base';
|
|
||||||
|
|
||||||
const MyPreset = definePreset(Aura, {
|
const MyPreset = definePreset(Aura, {
|
||||||
semantic: {
|
semantic: {
|
||||||
colorScheme: {
|
primary: {
|
||||||
primitive: {
|
50: '{blue.50}',
|
||||||
cyan: {
|
100: '{blue.100}',
|
||||||
50: '{cyan.50}',
|
200: '{blue.200}',
|
||||||
100: '{cyan.100}',
|
300: '{blue.300}',
|
||||||
200: '{cyan.200}',
|
400: '{blue.400}',
|
||||||
300: '{cyan.300}',
|
500: '{blue.500}',
|
||||||
400: '{cyan.400}',
|
600: '{blue.600}',
|
||||||
500: '{cyan.500}',
|
700: '{blue.700}',
|
||||||
}
|
800: '{blue.800}',
|
||||||
|
900: '{blue.900}',
|
||||||
},
|
950: '{blue.950}'
|
||||||
primary: {
|
|
||||||
50: '{zinc.50}',
|
|
||||||
100: '{zinc.100}',
|
|
||||||
200: '{zinc.200}',
|
|
||||||
300: '{zinc.300}',
|
|
||||||
400: '{zinc.400}',
|
|
||||||
500: '{zinc.500}',
|
|
||||||
600: '{zinc.600}',
|
|
||||||
700: '{zinc.700}',
|
|
||||||
800: '{zinc.800}',
|
|
||||||
900: '{zinc.900}',
|
|
||||||
950: '{zinc.950}'
|
|
||||||
},
|
},
|
||||||
|
colorScheme: {
|
||||||
|
|
||||||
|
|
||||||
light: {
|
light: {
|
||||||
surface: {
|
surface: {
|
||||||
0: '#ffffff',
|
0: '#ffffff',
|
||||||
50: '{zinc.50}',
|
50: '{blue.50}',
|
||||||
100: '{zinc.100}',
|
100: '{blue.100}',
|
||||||
200: '{zinc.200}',
|
200: '{blue.200}',
|
||||||
300: '{zinc.300}',
|
300: '{blue.300}',
|
||||||
400: '{zinc.400}',
|
400: '{blue.400}',
|
||||||
500: '{zinc.500}',
|
500: '{blue.500}',
|
||||||
600: '{zinc.600}',
|
600: '{blue.600}',
|
||||||
700: '{zinc.700}',
|
700: '{blue.700}',
|
||||||
800: '{zinc.800}',
|
800: '{blue.800}',
|
||||||
900: '{zinc.900}',
|
900: '{blue.900}',
|
||||||
950: '{zinc.950}'
|
950: '{blue.950}'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dark: {
|
dark: {
|
||||||
@@ -65,6 +55,7 @@ const MyPreset = definePreset(Aura, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-form-field {
|
.mat-form-field {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
td.mat-column-edit, .mat-column-delete {
|
td.mat-column-edit, .mat-column-delete {
|
||||||
width: 35px;
|
width: 35px;
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
<div class="shadow-2xl rounded p-2 mt-2">
|
<div class="shadow-2xl rounded p-2 mt-2">
|
||||||
<h3>Family Tree </h3>
|
<h3>Family Tree </h3>
|
||||||
<div>
|
<div>
|
||||||
<label>link from partner and Father and Mother Id</label>
|
<label>link from partner and Father and Mother Id</label>
|
||||||
<div >
|
<div >
|
||||||
<!--this styleclass all logic in api one not here. background color -->
|
<!--this styleclass all logic in api one not here. background color -->
|
||||||
<!--the treeNode.Data has treeData image and sex-->
|
<!--the treeNode.Data has treeData image and sex-->
|
||||||
<!--image is 64 string so to show 'data:image/png;base64,'imageStr' here -->
|
<!--image is 64 string so to show 'data:image/png;base64,'imageStr' here -->
|
||||||
<!-- selectionMode="multiple" [(selection)]="selectedNodes" -->
|
<!-- selectionMode="multiple" [(selection)]="selectedNodes" -->
|
||||||
<p-organization-chart [value]="familyTree()" [collapsible]="true">
|
<p-organization-chart [value]="familyTree()" [collapsible]="true">
|
||||||
<ng-template let-node pTemplate="default">
|
<ng-template let-node pTemplate="default">
|
||||||
<div #targetEl class="flex flex-col items-center">
|
<div #targetEl class="flex flex-col items-center">
|
||||||
@if (node.data.image != "")
|
@if (node.data.image != "")
|
||||||
{
|
{
|
||||||
<img (mouseover)="op.show($event, targetEl)" [src]= "node.data.image" class="mb-2 w-12 h-12 rounded-full " />
|
<img (mouseover)="op.show($event, targetEl)" [src]= "node.data.image" class="mb-2 w-12 h-12 rounded-full " />
|
||||||
}
|
}
|
||||||
<!--img src="https://primefaces.org/cdn/primeng/images/flag/flag_placeholder.png" [alt]="node.label" [class]="'flag' + ' flag-' + node.data" width="32" /-->
|
<!--img src="https://primefaces.org/cdn/primeng/images/flag/flag_placeholder.png" [alt]="node.label" [class]="'flag' + ' flag-' + node.data" width="32" /-->
|
||||||
<div class="mt-2 font-medium text-lg">{{ node.label }}</div>
|
<div class="mt-2 font-medium text-lg">{{ node.label }}</div>
|
||||||
<div>{{ node.data.sex }} </div>
|
<div>{{ node.data.sex }} </div>
|
||||||
<p-popover #op class="flex w-2/5 h-2/5">
|
<p-popover #op class="flex w-2/5 h-2/5">
|
||||||
@if (node.data.image != "")
|
@if (node.data.image != "")
|
||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<p-button (onClick)="op.hide()" icon="pi pi-times" [rounded]="true" [text]="true" severity="danger" class="flex justify-end mb-2" />
|
<p-button (onClick)="op.hide()" icon="pi pi-times" [rounded]="true" [text]="true" severity="danger" class="flex justify-end mb-2" />
|
||||||
<img [src]= "node.data.image" alt="person profile" />
|
<img [src]= "node.data.image" alt="person profile" />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</p-popover>
|
</p-popover>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-organization-chart>
|
</p-organization-chart>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<button pButton pRipple class="p-button-sm mr-2 p-button-success" type="button" icon="pi pi-sign-in" label="Close"
|
<button pButton pRipple class="p-button-sm mr-2 p-button-success" type="button" icon="pi pi-sign-in" label="Close"
|
||||||
(click)="close()"></button>
|
(click)="close()"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+256
-256
@@ -1,256 +1,256 @@
|
|||||||
import { Component, OnInit, OnDestroy, inject, ChangeDetectorRef, signal} from '@angular/core';
|
import { Component, OnInit, OnDestroy, inject, ChangeDetectorRef, signal} from '@angular/core';
|
||||||
|
|
||||||
import { StaffView ,StaffSearch, Person, RelationShip } from '../models';
|
import { StaffView ,StaffSearch, Person, RelationShip } from '../models';
|
||||||
import { OrganizationChartModule } from 'primeng/organizationchart';
|
import { OrganizationChartModule } from '@openng/optimus-ui/organizationchart';
|
||||||
|
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { PersonService } from './person.service';
|
import { PersonService } from './person.service';
|
||||||
import { TableModule } from 'primeng/table';
|
import { TableModule } from '@openng/optimus-ui/table';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { ButtonModule } from 'primeng/button';
|
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||||
import { TreeNode } from 'primeng/api';
|
import { TreeNode } from '@openng/optimus-ui/api';
|
||||||
import { InputTextModule } from 'primeng/inputtext';
|
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||||
import { DialogService, DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
|
import { DialogService, DynamicDialogConfig, DynamicDialogRef } from '@openng/optimus-ui/dynamicdialog';
|
||||||
import { PersonEdit } from './person.edit';
|
import { PersonEdit } from './person.edit';
|
||||||
import { MessageService } from 'primeng/api';
|
import { MessageService } from '@openng/optimus-ui/api';
|
||||||
import { TreeModule, TreeNodeDoubleClickEvent, TreeNodeSelectEvent } from 'primeng/tree';
|
import { TreeModule, TreeNodeDoubleClickEvent, TreeNodeSelectEvent } from '@openng/optimus-ui/tree';
|
||||||
import { Utils } from '../shares';
|
import { Utils } from '../shares';
|
||||||
import { PopoverModule } from 'primeng/popover';
|
import { PopoverModule } from '@openng/optimus-ui/popover';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'family-orga',
|
selector: 'family-orga',
|
||||||
templateUrl: './family.orga.html',
|
templateUrl: './family.orga.html',
|
||||||
imports:[TableModule,FormsModule,TreeModule,PopoverModule, OrganizationChartModule,CommonModule,ButtonModule,InputTextModule],
|
imports:[TableModule,FormsModule,TreeModule,PopoverModule, OrganizationChartModule,CommonModule,ButtonModule,InputTextModule],
|
||||||
styleUrls: ['./family.orga.css'],
|
styleUrls: ['./family.orga.css'],
|
||||||
providers: [DialogService]
|
providers: [DialogService]
|
||||||
})
|
})
|
||||||
export class FamilyOrga implements OnInit, OnDestroy{
|
export class FamilyOrga implements OnInit, OnDestroy{
|
||||||
|
|
||||||
private subscription:Subscription = new Subscription();
|
private subscription:Subscription = new Subscription();
|
||||||
person!: Person;
|
person!: Person;
|
||||||
selectedNode!: TreeNode;
|
selectedNode!: TreeNode;
|
||||||
selectedNodes!: TreeNode[];
|
selectedNodes!: TreeNode[];
|
||||||
private cd = inject(ChangeDetectorRef);
|
private cd = inject(ChangeDetectorRef);
|
||||||
familyTree = signal<TreeNode[]>([]);
|
familyTree = signal<TreeNode[]>([]);
|
||||||
relations: RelationShip[] =[];
|
relations: RelationShip[] =[];
|
||||||
_id = -10;
|
_id = -10;
|
||||||
loading = false;
|
loading = false;
|
||||||
familyList:Person[] = [];
|
familyList:Person[] = [];
|
||||||
msg ="[Person organise component]";
|
msg ="[Person organise component]";
|
||||||
private messageService = inject(MessageService);
|
private messageService = inject(MessageService);
|
||||||
public ref = inject(DynamicDialogRef);
|
public ref = inject(DynamicDialogRef);
|
||||||
public config = inject(DynamicDialogConfig);
|
public config = inject(DynamicDialogConfig);
|
||||||
/*
|
/*
|
||||||
private store: Store<appValidationState>
|
private store: Store<appValidationState>
|
||||||
*/
|
*/
|
||||||
private personService = inject(PersonService);
|
private personService = inject(PersonService);
|
||||||
public dialogService = inject(DialogService);
|
public dialogService = inject(DialogService);
|
||||||
|
|
||||||
ngOnInit(): void
|
ngOnInit(): void
|
||||||
{
|
{
|
||||||
const id = this.config.data.id;
|
const id = this.config.data.id;
|
||||||
this.familyList = this.config.data.familyList;
|
this.familyList = this.config.data.familyList;
|
||||||
const item = this.familyList.find(x => x.id == id);
|
const item = this.familyList.find(x => x.id == id);
|
||||||
if (item != undefined)
|
if (item != undefined)
|
||||||
this.person = item;
|
this.person = item;
|
||||||
this.loadPersonFamilyTree(id);
|
this.loadPersonFamilyTree(id);
|
||||||
//this.populateTree();
|
//this.populateTree();
|
||||||
|
|
||||||
}
|
}
|
||||||
populateTree() : void {
|
populateTree() : void {
|
||||||
const data: TreeNode[] = [
|
const data: TreeNode[] = [
|
||||||
{
|
{
|
||||||
expanded: true,
|
expanded: true,
|
||||||
type: 'person',
|
type: 'person',
|
||||||
styleClass: 'bg-indigo-500 text-white',
|
styleClass: 'bg-blue-500 text-white',
|
||||||
data: {
|
data: {
|
||||||
image: 'https://primefaces.org/cdn/primeng/images/demo/avatar/amyelsner.png',
|
image: 'https://primefaces.org/cdn/primeng/images/demo/avatar/amyelsner.png',
|
||||||
name: 'Amy Elsner',
|
name: 'Amy Elsner',
|
||||||
title: 'CEO'
|
title: 'CEO'
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
expanded: true,
|
expanded: true,
|
||||||
type: 'person',
|
type: 'person',
|
||||||
styleClass: 'bg-purple-500 text-white',
|
styleClass: 'bg-purple-500 text-white',
|
||||||
data: {
|
data: {
|
||||||
image: 'https://primefaces.org/cdn/primeng/images/demo/avatar/annafali.png',
|
image: 'https://primefaces.org/cdn/primeng/images/demo/avatar/annafali.png',
|
||||||
name: 'Anna Fali',
|
name: 'Anna Fali',
|
||||||
title: 'CMO'
|
title: 'CMO'
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'Sales',
|
label: 'Sales',
|
||||||
styleClass: 'bg-purple-500 text-white',
|
styleClass: 'bg-purple-500 text-white',
|
||||||
style: ' border-radius: 12px'
|
style: ' border-radius: 12px'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Marketing',
|
label: 'Marketing',
|
||||||
styleClass: 'bg-purple-500 text-white',
|
styleClass: 'bg-purple-500 text-white',
|
||||||
style: ' border-radius: 12px'
|
style: ' border-radius: 12px'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expanded: true,
|
expanded: true,
|
||||||
type: 'person',
|
type: 'person',
|
||||||
styleClass: 'bg-teal-500 text-white',
|
styleClass: 'bg-teal-500 text-white',
|
||||||
data: {
|
data: {
|
||||||
image: 'https://primefaces.org/cdn/primeng/images/demo/avatar/stephenshaw.png',
|
image: 'https://primefaces.org/cdn/primeng/images/demo/avatar/stephenshaw.png',
|
||||||
name: 'Stephen Shaw',
|
name: 'Stephen Shaw',
|
||||||
title: 'CTO'
|
title: 'CTO'
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
label: 'Development',
|
label: 'Development',
|
||||||
styleClass: 'bg-teal-500 text-white'
|
styleClass: 'bg-teal-500 text-white'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'UI/UX Design',
|
label: 'UI/UX Design',
|
||||||
styleClass: 'bg-teal-500 text-white'
|
styleClass: 'bg-teal-500 text-white'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.familyTree.set(data);
|
this.familyTree.set(data);
|
||||||
}
|
}
|
||||||
loadPersonFamilyTree(id: number): void {
|
loadPersonFamilyTree(id: number): void {
|
||||||
const relationShip$ = this.personService.loadPersonFamily(id);
|
const relationShip$ = this.personService.loadPersonFamily(id);
|
||||||
this.subscription.add(relationShip$.subscribe(
|
this.subscription.add(relationShip$.subscribe(
|
||||||
{
|
{
|
||||||
next: x => {
|
next: x => {
|
||||||
if (x.statusCode == 1)
|
if (x.statusCode == 1)
|
||||||
{
|
{
|
||||||
let tree : TreeNode[] =[];
|
let tree : TreeNode[] =[];
|
||||||
tree.push(x.data);
|
tree.push(x.data);
|
||||||
this.familyTree.set(tree);
|
this.familyTree.set(tree);
|
||||||
console.log("load person family", this.familyTree());
|
console.log("load person family", this.familyTree());
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: e => {
|
error: e => {
|
||||||
console.error("error load loadPersonFamily by personId", id);
|
console.error("error load loadPersonFamily by personId", id);
|
||||||
this.messageService.add({severity:'error', summary: 'error load loadPersonFamily by personId', detail: e.message});
|
this.messageService.add({severity:'error', summary: 'error load loadPersonFamily by personId', detail: e.message});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeSelect(event: TreeNodeSelectEvent) {
|
nodeSelect(event: TreeNodeSelectEvent) {
|
||||||
// this.messageService.add({ severity: 'info', summary: 'Node Selected', detail: event.node.label });
|
// this.messageService.add({ severity: 'info', summary: 'Node Selected', detail: event.node.label });
|
||||||
}
|
}
|
||||||
nodeDoubleSelect(event:TreeNodeDoubleClickEvent) : void {
|
nodeDoubleSelect(event:TreeNodeDoubleClickEvent) : void {
|
||||||
// console.log("double click node", event.node.key);
|
// console.log("double click node", event.node.key);
|
||||||
const id = event.node.key;
|
const id = event.node.key;
|
||||||
this.edit(Number(id));
|
this.edit(Number(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
getName(id:number): string
|
getName(id:number): string
|
||||||
{
|
{
|
||||||
let result ="";
|
let result ="";
|
||||||
const item = this.familyList.find(x => x.id == id);
|
const item = this.familyList.find(x => x.id == id);
|
||||||
if (item)
|
if (item)
|
||||||
result = item.lastName + " " + item.firstName;
|
result = item.lastName + " " + item.firstName;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
updateParent(list:Person[]):void {
|
updateParent(list:Person[]):void {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let item:Person;
|
let item:Person;
|
||||||
for (i = 0; i< list.length; i++)
|
for (i = 0; i< list.length; i++)
|
||||||
{
|
{
|
||||||
item = list[i];
|
item = list[i];
|
||||||
if (item.fatherId && item.fatherId > 0)
|
if (item.fatherId && item.fatherId > 0)
|
||||||
{
|
{
|
||||||
item.fatherName = this.getName(item.fatherId);
|
item.fatherName = this.getName(item.fatherId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newFamily():void {
|
newFamily():void {
|
||||||
//console.log("add new employee");
|
//console.log("add new employee");
|
||||||
this.personService.parentList = this.familyList;
|
this.personService.parentList = this.familyList;
|
||||||
// this.router.navigate( ['/family/new'], { queryParams: {returnUrl:'/family' } });
|
// this.router.navigate( ['/family/new'], { queryParams: {returnUrl:'/family' } });
|
||||||
this.showEdit(this._id--);
|
this.showEdit(this._id--);
|
||||||
}
|
}
|
||||||
edit(id: number) : void {
|
edit(id: number) : void {
|
||||||
//console.log("edit family", id);
|
//console.log("edit family", id);
|
||||||
this.personService.parentList = this.familyList;
|
this.personService.parentList = this.familyList;
|
||||||
// this.router.navigate( ['/family/'+id], { queryParams: {returnUrl:'/family' } });
|
// this.router.navigate( ['/family/'+id], { queryParams: {returnUrl:'/family' } });
|
||||||
this.showEdit(id);
|
this.showEdit(id);
|
||||||
}
|
}
|
||||||
showEdit(id:number) {
|
showEdit(id:number) {
|
||||||
const ref = this.dialogService.open(PersonEdit, {
|
const ref = this.dialogService.open(PersonEdit, {
|
||||||
data: {
|
data: {
|
||||||
id,
|
id,
|
||||||
familyList: this.familyList,
|
familyList: this.familyList,
|
||||||
},
|
},
|
||||||
header: 'Family',
|
header: 'Family',
|
||||||
width: '80%',
|
width: '80%',
|
||||||
maximizable: true
|
maximizable: true
|
||||||
});
|
});
|
||||||
if (ref)
|
if (ref)
|
||||||
{
|
{
|
||||||
ref.onClose.subscribe((item: Person) => {
|
ref.onClose.subscribe((item: Person) => {
|
||||||
if (item) {
|
if (item) {
|
||||||
//console.log("after close ward edit", item);
|
//console.log("after close ward edit", item);
|
||||||
this.messageService.add({severity:'success', summary: 'Save Family', detail: item.firstName!});
|
this.messageService.add({severity:'success', summary: 'Save Family', detail: item.firstName!});
|
||||||
//update the current list
|
//update the current list
|
||||||
this.updateList(item);
|
this.updateList(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateList(item: Person) :void {
|
updateList(item: Person) :void {
|
||||||
const idx = this.familyList.findIndex( x => x.id == item.id);
|
const idx = this.familyList.findIndex( x => x.id == item.id);
|
||||||
if (item.fatherId && item.fatherId > 0)
|
if (item.fatherId && item.fatherId > 0)
|
||||||
item.fatherName = this.getName(item.fatherId);
|
item.fatherName = this.getName(item.fatherId);
|
||||||
if (item.motherId && item.motherId > 0)
|
if (item.motherId && item.motherId > 0)
|
||||||
item.motherName = this.getName(item.motherId);
|
item.motherName = this.getName(item.motherId);
|
||||||
if (idx < 0)
|
if (idx < 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
const olist = [... this.familyList, item];
|
const olist = [... this.familyList, item];
|
||||||
this.familyList = olist;
|
this.familyList = olist;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const oitem = this.familyList[idx];
|
const oitem = this.familyList[idx];
|
||||||
oitem.firstName = item.firstName;
|
oitem.firstName = item.firstName;
|
||||||
oitem.lastName = item.lastName;
|
oitem.lastName = item.lastName;
|
||||||
oitem.address = item.address;
|
oitem.address = item.address;
|
||||||
oitem.alive = item.alive;
|
oitem.alive = item.alive;
|
||||||
oitem.dob = item.dob;
|
oitem.dob = item.dob;
|
||||||
oitem.email = item.email;
|
oitem.email = item.email;
|
||||||
oitem.fatherId = item.fatherId;
|
oitem.fatherId = item.fatherId;
|
||||||
oitem.motherId = item.motherId;
|
oitem.motherId = item.motherId;
|
||||||
oitem.motherName = item.motherName;
|
oitem.motherName = item.motherName;
|
||||||
oitem.fatherName = item.fatherName;
|
oitem.fatherName = item.fatherName;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deleteItem(id: number): void {
|
deleteItem(id: number): void {
|
||||||
this.personService.deletePerson(id)
|
this.personService.deletePerson(id)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe({ next: result => {
|
.subscribe({ next: result => {
|
||||||
console.log(this.msg + " deleteItem success", result);
|
console.log(this.msg + " deleteItem success", result);
|
||||||
|
|
||||||
const nlist = this.familyList.filter(d => d.id !== id);
|
const nlist = this.familyList.filter(d => d.id !== id);
|
||||||
this.familyList = nlist;
|
this.familyList = nlist;
|
||||||
},
|
},
|
||||||
error: e => console.error(e)
|
error: e => console.error(e)
|
||||||
});
|
});
|
||||||
//console.log(this.msg + "click button to delete");
|
//console.log(this.msg + "click button to delete");
|
||||||
}
|
}
|
||||||
close() :void {
|
close() :void {
|
||||||
this.ref.close(null);
|
this.ref.close(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.subscription.unsubscribe();
|
this.subscription.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-form-field {
|
.mat-form-field {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
td.mat-column-edit, .mat-column-delete {
|
td.mat-column-edit, .mat-column-delete {
|
||||||
width: 35px;
|
width: 35px;
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
<div class="shadow-2xl rounded p-2 mt-2">
|
<div class="shadow-2xl rounded p-2 mt-2">
|
||||||
<h3>Family Tree by Person has Father</h3>
|
<h3>Family Tree by Person has Father</h3>
|
||||||
<div>
|
<div>
|
||||||
<form>
|
<form>
|
||||||
<div class="grid grid-cols-12 gap-2">
|
<div class="grid grid-cols-12 gap-2">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<p-checkbox inputId="isFather" [binary]="true" name="isFather" [(ngModel)]="isFather" />
|
<p-checkbox inputId="isFather" [binary]="true" name="isFather" [(ngModel)]="isFather" />
|
||||||
<label for="isFather" class="ml-2"> Is Father </label>
|
<label for="isFather" class="ml-2"> Is Father </label>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-end">
|
<div class="flex items-end">
|
||||||
<button pButton pRipple class="p-button-sm mr-2 " type="submit" icon="pi pi-sitemap" label="Load"
|
<button pButton pRipple class="p-button-sm mr-2 " type="submit" icon="pi pi-sitemap" label="Load"
|
||||||
(click)="load()"></button>
|
(click)="load()"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p-tree [value]="familyTree" class="w-full md:w-[30rem]"
|
<p-tree [value]="familyTree" class="w-full md:w-[30rem]"
|
||||||
(onNodeDoubleClick)="nodeDoubleSelect($event)"
|
(onNodeDoubleClick)="nodeDoubleSelect($event)"
|
||||||
selectionMode="single" [(selection)]="selectedNode" (onNodeSelect)="nodeSelect($event)" />
|
selectionMode="single" [(selection)]="selectedNode" (onNodeSelect)="nodeSelect($event)" />
|
||||||
<!--div class="card flex justify-center overflow-x-auto">
|
<!--div class="card flex justify-center overflow-x-auto">
|
||||||
<p-organization-chart [value]="familyTree" selectionMode="multiple" [(selection)]="selectedNodes" [collapsible]="true">
|
<p-organization-chart [value]="familyTree" selectionMode="multiple" [(selection)]="selectedNodes" [collapsible]="true">
|
||||||
<ng-template let-node pTemplate="person">
|
<ng-template let-node pTemplate="person">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
<img [src]="node.data.image" class="mb-4 w-12 h-12" />
|
<img [src]="node.data.image" class="mb-4 w-12 h-12" />
|
||||||
<div class="font-bold mb-2">{{ node.data.name }}</div>
|
<div class="font-bold mb-2">{{ node.data.name }}</div>
|
||||||
<div>{{ node.data.title }}</div>
|
<div>{{ node.data.title }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-organization-chart>
|
</p-organization-chart>
|
||||||
</div-->
|
</div-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+227
-227
@@ -1,227 +1,227 @@
|
|||||||
import { Component, OnInit, OnDestroy, inject, ChangeDetectorRef, signal} from '@angular/core';
|
import { Component, OnInit, OnDestroy, inject, ChangeDetectorRef, signal} from '@angular/core';
|
||||||
|
|
||||||
import { StaffView ,StaffSearch, Person } from '../models';
|
import { StaffView ,StaffSearch, Person } from '../models';
|
||||||
import { OrganizationChartModule } from 'primeng/organizationchart';
|
import { OrganizationChartModule } from '@openng/optimus-ui/organizationchart';
|
||||||
|
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { PersonService } from './person.service';
|
import { PersonService } from './person.service';
|
||||||
import { AuthenticationService } from '../user-services';
|
import { AuthenticationService } from '../user-services';
|
||||||
import { TableModule } from 'primeng/table';
|
import { TableModule } from '@openng/optimus-ui/table';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { ButtonModule } from 'primeng/button';
|
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||||
import { TreeNode } from 'primeng/api';
|
import { TreeNode } from '@openng/optimus-ui/api';
|
||||||
import { InputTextModule } from 'primeng/inputtext';
|
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||||
import { DialogService } from 'primeng/dynamicdialog';
|
import { DialogService } from '@openng/optimus-ui/dynamicdialog';
|
||||||
import { PersonEdit } from './person.edit';
|
import { PersonEdit } from './person.edit';
|
||||||
import { MessageService } from 'primeng/api';
|
import { MessageService } from '@openng/optimus-ui/api';
|
||||||
import { CheckboxModule } from 'primeng/checkbox';
|
import { CheckboxModule } from '@openng/optimus-ui/checkbox';
|
||||||
import { TreeModule, TreeNodeDoubleClickEvent, TreeNodeSelectEvent } from 'primeng/tree';
|
import { TreeModule, TreeNodeDoubleClickEvent, TreeNodeSelectEvent } from '@openng/optimus-ui/tree';
|
||||||
import { Utils } from '../shares';
|
import { Utils } from '../shares';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'family-tree',
|
selector: 'family-tree',
|
||||||
templateUrl: './family.tree.html',
|
templateUrl: './family.tree.html',
|
||||||
imports:[TableModule,FormsModule,TreeModule,CheckboxModule,
|
imports:[TableModule,FormsModule,TreeModule,CheckboxModule,
|
||||||
OrganizationChartModule,CommonModule,
|
OrganizationChartModule,CommonModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ButtonModule,InputTextModule],
|
ButtonModule,InputTextModule],
|
||||||
styleUrls: ['./family.tree.css'],
|
styleUrls: ['./family.tree.css'],
|
||||||
providers: [DialogService]
|
providers: [DialogService]
|
||||||
})
|
})
|
||||||
export class FamilyTree implements OnInit, OnDestroy{
|
export class FamilyTree implements OnInit, OnDestroy{
|
||||||
isFather = signal(true);
|
isFather = signal(true);
|
||||||
private subscription:Subscription = new Subscription();
|
private subscription:Subscription = new Subscription();
|
||||||
firstname = '';
|
firstname = '';
|
||||||
selectedNode!: TreeNode;
|
selectedNode!: TreeNode;
|
||||||
private cd = inject(ChangeDetectorRef);
|
private cd = inject(ChangeDetectorRef);
|
||||||
familyTree: TreeNode[] = [];
|
familyTree: TreeNode[] = [];
|
||||||
email = '';
|
email = '';
|
||||||
lastname = '';
|
lastname = '';
|
||||||
_id = -10;
|
_id = -10;
|
||||||
loading = false;
|
loading = false;
|
||||||
familyList:Person[] = [];
|
familyList:Person[] = [];
|
||||||
msg ="[Person tree component]";
|
msg ="[Person tree component]";
|
||||||
private messageService = inject(MessageService);
|
private messageService = inject(MessageService);
|
||||||
/*
|
/*
|
||||||
private store: Store<appValidationState>
|
private store: Store<appValidationState>
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
public dialogService: DialogService,
|
public dialogService: DialogService,
|
||||||
private personService: PersonService,
|
private personService: PersonService,
|
||||||
private authenticationService: AuthenticationService,
|
private authenticationService: AuthenticationService,
|
||||||
private router: Router
|
private router: Router
|
||||||
) {}
|
) {}
|
||||||
getSearchCiteria(): StaffSearch {
|
getSearchCiteria(): StaffSearch {
|
||||||
let criteria:StaffSearch = {
|
let criteria:StaffSearch = {
|
||||||
email: this.email,
|
email: this.email,
|
||||||
firstName: this.firstname,
|
firstName: this.firstname,
|
||||||
lastName: this.lastname,
|
lastName: this.lastname,
|
||||||
};
|
};
|
||||||
|
|
||||||
return criteria;
|
return criteria;
|
||||||
|
|
||||||
}
|
}
|
||||||
canSearch():boolean {
|
canSearch():boolean {
|
||||||
let result = false;
|
let result = false;
|
||||||
result = this.email !== "";
|
result = this.email !== "";
|
||||||
result = result || this.lastname !== "";
|
result = result || this.lastname !== "";
|
||||||
result = result || this.firstname !== "";
|
result = result || this.firstname !== "";
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
ngOnInit(): void
|
ngOnInit(): void
|
||||||
{
|
{
|
||||||
this.authenticationService.isHome = false;
|
this.authenticationService.isHome = false;
|
||||||
this.authenticationService.isReport = false;
|
this.authenticationService.isReport = false;
|
||||||
const prev = this.personService.searchCriteria;
|
const prev = this.personService.searchCriteria;
|
||||||
let goload = true;
|
let goload = true;
|
||||||
this.load();
|
this.load();
|
||||||
|
|
||||||
}
|
}
|
||||||
getActive(active:boolean):string {
|
getActive(active:boolean):string {
|
||||||
let result = 'false-icon pi-times-circle';
|
let result = 'false-icon pi-times-circle';
|
||||||
if (active)
|
if (active)
|
||||||
result = 'true-icon pi-check-circle';
|
result = 'true-icon pi-check-circle';
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
load():void {
|
load():void {
|
||||||
let father = this.isFather();
|
let father = this.isFather();
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
//const criteria = this.getSearchCiteria();
|
//const criteria = this.getSearchCiteria();
|
||||||
// this.personService.searchCriteria = criteria;
|
// this.personService.searchCriteria = criteria;
|
||||||
this.subscription.add(
|
this.subscription.add(
|
||||||
this.personService.loadPersonFamilyTree(father, !father).subscribe(
|
this.personService.loadPersonFamilyTree(father, !father).subscribe(
|
||||||
{
|
{
|
||||||
next: x => {
|
next: x => {
|
||||||
if (x.statusCode == 1)
|
if (x.statusCode == 1)
|
||||||
{
|
{
|
||||||
this.familyTree = x.data;
|
this.familyTree = x.data;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.cd.detectChanges();
|
this.cd.detectChanges();
|
||||||
console.log("the family tree", this.familyTree);
|
console.log("the family tree", this.familyTree);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
error: e => {
|
error: e => {
|
||||||
const message = e || e.message;
|
const message = e || e.message;
|
||||||
// this.toastr.error(message);
|
// this.toastr.error(message);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
console.log("error ", e);
|
console.log("error ", e);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeSelect(event: TreeNodeSelectEvent) {
|
nodeSelect(event: TreeNodeSelectEvent) {
|
||||||
// this.messageService.add({ severity: 'info', summary: 'Node Selected', detail: event.node.label });
|
// this.messageService.add({ severity: 'info', summary: 'Node Selected', detail: event.node.label });
|
||||||
}
|
}
|
||||||
nodeDoubleSelect(event:TreeNodeDoubleClickEvent) : void {
|
nodeDoubleSelect(event:TreeNodeDoubleClickEvent) : void {
|
||||||
// console.log("double click node", event.node.key);
|
// console.log("double click node", event.node.key);
|
||||||
const id = event.node.key;
|
const id = event.node.key;
|
||||||
this.edit(Number(id));
|
this.edit(Number(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
getName(id:number): string
|
getName(id:number): string
|
||||||
{
|
{
|
||||||
let result ="";
|
let result ="";
|
||||||
const item = this.familyList.find(x => x.id == id);
|
const item = this.familyList.find(x => x.id == id);
|
||||||
if (item)
|
if (item)
|
||||||
result = item.lastName + " " + item.firstName;
|
result = item.lastName + " " + item.firstName;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
updateParent(list:Person[]):void {
|
updateParent(list:Person[]):void {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let item:Person;
|
let item:Person;
|
||||||
for (i = 0; i< list.length; i++)
|
for (i = 0; i< list.length; i++)
|
||||||
{
|
{
|
||||||
item = list[i];
|
item = list[i];
|
||||||
if (item.fatherId && item.fatherId > 0)
|
if (item.fatherId && item.fatherId > 0)
|
||||||
{
|
{
|
||||||
item.fatherName = this.getName(item.fatherId);
|
item.fatherName = this.getName(item.fatherId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newFamily():void {
|
newFamily():void {
|
||||||
//console.log("add new employee");
|
//console.log("add new employee");
|
||||||
this.personService.parentList = this.familyList;
|
this.personService.parentList = this.familyList;
|
||||||
// this.router.navigate( ['/family/new'], { queryParams: {returnUrl:'/family' } });
|
// this.router.navigate( ['/family/new'], { queryParams: {returnUrl:'/family' } });
|
||||||
this.showEdit(this._id--);
|
this.showEdit(this._id--);
|
||||||
}
|
}
|
||||||
edit(id: number) : void {
|
edit(id: number) : void {
|
||||||
//console.log("edit family", id);
|
//console.log("edit family", id);
|
||||||
this.personService.parentList = this.familyList;
|
this.personService.parentList = this.familyList;
|
||||||
// this.router.navigate( ['/family/'+id], { queryParams: {returnUrl:'/family' } });
|
// this.router.navigate( ['/family/'+id], { queryParams: {returnUrl:'/family' } });
|
||||||
this.showEdit(id);
|
this.showEdit(id);
|
||||||
}
|
}
|
||||||
showEdit(id:number) {
|
showEdit(id:number) {
|
||||||
const ref = this.dialogService.open(PersonEdit, {
|
const ref = this.dialogService.open(PersonEdit, {
|
||||||
data: {
|
data: {
|
||||||
id,
|
id,
|
||||||
familyList: this.familyList,
|
familyList: this.familyList,
|
||||||
},
|
},
|
||||||
header: 'Family',
|
header: 'Family',
|
||||||
width: '80%',
|
width: '80%',
|
||||||
maximizable: true
|
maximizable: true
|
||||||
});
|
});
|
||||||
if (ref)
|
if (ref)
|
||||||
{
|
{
|
||||||
ref.onClose.subscribe((item: Person) => {
|
ref.onClose.subscribe((item: Person) => {
|
||||||
if (item) {
|
if (item) {
|
||||||
//console.log("after close ward edit", item);
|
//console.log("after close ward edit", item);
|
||||||
this.messageService.add({severity:'success', summary: 'Save Family', detail: item.firstName!});
|
this.messageService.add({severity:'success', summary: 'Save Family', detail: item.firstName!});
|
||||||
//update the current list
|
//update the current list
|
||||||
this.updateList(item);
|
this.updateList(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateList(item: Person) :void {
|
updateList(item: Person) :void {
|
||||||
const idx = this.familyList.findIndex( x => x.id == item.id);
|
const idx = this.familyList.findIndex( x => x.id == item.id);
|
||||||
if (item.fatherId && item.fatherId > 0)
|
if (item.fatherId && item.fatherId > 0)
|
||||||
item.fatherName = this.getName(item.fatherId);
|
item.fatherName = this.getName(item.fatherId);
|
||||||
if (item.motherId && item.motherId > 0)
|
if (item.motherId && item.motherId > 0)
|
||||||
item.motherName = this.getName(item.motherId);
|
item.motherName = this.getName(item.motherId);
|
||||||
if (idx < 0)
|
if (idx < 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
const olist = [... this.familyList, item];
|
const olist = [... this.familyList, item];
|
||||||
this.familyList = olist;
|
this.familyList = olist;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const oitem = this.familyList[idx];
|
const oitem = this.familyList[idx];
|
||||||
oitem.firstName = item.firstName;
|
oitem.firstName = item.firstName;
|
||||||
oitem.lastName = item.lastName;
|
oitem.lastName = item.lastName;
|
||||||
oitem.address = item.address;
|
oitem.address = item.address;
|
||||||
oitem.alive = item.alive;
|
oitem.alive = item.alive;
|
||||||
oitem.dob = item.dob;
|
oitem.dob = item.dob;
|
||||||
oitem.email = item.email;
|
oitem.email = item.email;
|
||||||
oitem.fatherId = item.fatherId;
|
oitem.fatherId = item.fatherId;
|
||||||
oitem.motherId = item.motherId;
|
oitem.motherId = item.motherId;
|
||||||
oitem.motherName = item.motherName;
|
oitem.motherName = item.motherName;
|
||||||
oitem.fatherName = item.fatherName;
|
oitem.fatherName = item.fatherName;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deleteItem(id: number): void {
|
deleteItem(id: number): void {
|
||||||
this.personService.deletePerson(id)
|
this.personService.deletePerson(id)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe({ next: result => {
|
.subscribe({ next: result => {
|
||||||
console.log(this.msg + " deleteItem success", result);
|
console.log(this.msg + " deleteItem success", result);
|
||||||
|
|
||||||
const nlist = this.familyList.filter(d => d.id !== id);
|
const nlist = this.familyList.filter(d => d.id !== id);
|
||||||
this.familyList = nlist;
|
this.familyList = nlist;
|
||||||
},
|
},
|
||||||
error: e => console.error(e)
|
error: e => console.error(e)
|
||||||
});
|
});
|
||||||
//console.log(this.msg + "click button to delete");
|
//console.log(this.msg + "click button to delete");
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.subscription.unsubscribe();
|
this.subscription.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-form-field {
|
.mat-form-field {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
td.mat-column-edit, .mat-column-delete {
|
td.mat-column-edit, .mat-column-delete {
|
||||||
width: 35px;
|
width: 35px;
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,86 +1,86 @@
|
|||||||
<div class="shadow-2xl rounded p-2 mt-2">
|
<div class="shadow-2xl rounded p-2 mt-2">
|
||||||
<h3>Person List</h3>
|
<h3>Person List</h3>
|
||||||
<div>
|
<div>
|
||||||
<form>
|
<form>
|
||||||
<div class="grid md:grid-cols-4 gap-2">
|
<div class="grid md:grid-cols-4 gap-2">
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="login">Email</label>
|
<label for="login">Email</label>
|
||||||
<input id="login" pInputText name="login" type="text" [(ngModel)]="email"
|
<input id="login" pInputText name="login" type="text" [(ngModel)]="email"
|
||||||
class="inputfield w-full p-inputtext-sm">
|
class="inputfield w-full p-inputtext-sm">
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="lastname1">Surname</label>
|
<label for="lastname1">Surname</label>
|
||||||
<input id="lastname1" pInputText name="lastname" type="text" [(ngModel)]="lastname"
|
<input id="lastname1" pInputText name="lastname" type="text" [(ngModel)]="lastname"
|
||||||
class="inputfield w-full p-inputtext-sm">
|
class="inputfield w-full p-inputtext-sm">
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="firstname">First Name</label>
|
<label for="firstname">First Name</label>
|
||||||
<input id="firstname" name="firstname" pInputText type="text" [(ngModel)]="firstname"
|
<input id="firstname" name="firstname" pInputText type="text" [(ngModel)]="firstname"
|
||||||
class="inputfield w-full p-inputtext-sm">
|
class="inputfield w-full p-inputtext-sm">
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-end">
|
<div class="flex items-end">
|
||||||
<button pButton pRipple class="p-button-sm mr-2 " type="submit" icon="pi pi-search" iconPos="left" label="Search"
|
<button pButton pRipple class="p-button-sm mr-2 " type="submit" icon="pi pi-search" iconPos="left" label="Search"
|
||||||
(click)="search()"></button>
|
(click)="search()"></button>
|
||||||
<button pButton pRipple class="p-button-sm " type="button" icon="pi pi-user-plus" label="New Person"
|
<button pButton pRipple class="p-button-sm " type="button" icon="pi pi-user-plus" label="New Person"
|
||||||
(click)="newFamily()"></button>
|
(click)="newFamily()"></button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p-table [value]="familyList()" sortMode="multiple" dataKey="id" class="p-datatable-sm" #dt
|
<p-table [value]="familyList()" sortMode="multiple" dataKey="id" class="p-datatable-sm" #dt
|
||||||
class="p-datatable-sm" selectionMode="single" [(selection)]="selectedPerson"
|
class="p-datatable-sm" selectionMode="single" [(selection)]="selectedPerson"
|
||||||
[paginator]="true" rowHover="true" [globalFilterFields]="['lastName', 'firstName', 'email', 'fatherName', 'motherName']"
|
[paginator]="true" rowHover="true" [globalFilterFields]="['lastName', 'firstName', 'email', 'fatherName', 'motherName']"
|
||||||
[rows]="20" [rowsPerPageOptions]="[10,20,50,100]"
|
[rows]="20" [rowsPerPageOptions]="[10,20,50,100]"
|
||||||
[loading]="loading">
|
[loading]="loading">
|
||||||
<ng-template #caption>
|
<ng-template #caption>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<p-button icon="pi pi-external-link" label="Export" (click)="exportExport()"
|
<p-button icon="pi pi-external-link" label="Export" (click)="exportExport()"
|
||||||
/>
|
/>
|
||||||
<p-iconfield iconPosition="left" class="ml-auto">
|
<p-iconfield iconPosition="left" class="ml-auto">
|
||||||
<p-inputicon>
|
<p-inputicon>
|
||||||
<i class="pi pi-search"></i>
|
<i class="pi pi-search"></i>
|
||||||
</p-inputicon>
|
</p-inputicon>
|
||||||
<input pInputText type="text" (input)="handleInput($event)" placeholder="Search keyword" />
|
<input pInputText type="text" (input)="handleInput($event)" placeholder="Search keyword" />
|
||||||
</p-iconfield>
|
</p-iconfield>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template pTemplate="header">
|
<ng-template pTemplate="header">
|
||||||
<tr>
|
<tr>
|
||||||
|
|
||||||
<th pSortableColumn="lastName">Last Name <p-sortIcon field="lastName"></p-sortIcon>
|
<th pSortableColumn="lastName">Last Name <p-sortIcon field="lastName"></p-sortIcon>
|
||||||
</th>
|
</th>
|
||||||
<th pSortableColumn="firstName">First Name <p-sortIcon field="firstName"></p-sortIcon>
|
<th pSortableColumn="firstName">First Name <p-sortIcon field="firstName"></p-sortIcon>
|
||||||
</th>
|
</th>
|
||||||
<th pSortableColumn="sex">Sex <p-sortIcon field="sex"></p-sortIcon></th>
|
<th pSortableColumn="sex">Sex <p-sortIcon field="sex"></p-sortIcon></th>
|
||||||
<th pSortableColumn="fatherName">Father<p-sortIcon field="fatherName"></p-sortIcon>
|
<th pSortableColumn="fatherName">Father<p-sortIcon field="fatherName"></p-sortIcon>
|
||||||
</th>
|
</th>
|
||||||
<th pSortableColumn="motherName">Mother<p-sortIcon field="motherName"></p-sortIcon>
|
<th pSortableColumn="motherName">Mother<p-sortIcon field="motherName"></p-sortIcon>
|
||||||
</th>
|
</th>
|
||||||
|
|
||||||
<th>Edit</th>
|
<th>Edit</th>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template pTemplate="body" let-user>
|
<ng-template pTemplate="body" let-user>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{user.lastName}}</td>
|
<td>{{user.lastName}}</td>
|
||||||
<td>{{user.firstName}}</td>
|
<td>{{user.firstName}}</td>
|
||||||
<td>{{user.sex}}</td>
|
<td>{{user.sex}}</td>
|
||||||
<td>{{user.fatherName}}</td>
|
<td>{{user.fatherName}}</td>
|
||||||
<td>{{user.motherName}}</td>
|
<td>{{user.motherName}}</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<p-button type="button" icon="pi pi-ellipsis-v"
|
<p-button type="button" icon="pi pi-ellipsis-v"
|
||||||
[rounded]="true" [text]="true" [raised]="true"
|
[rounded]="true" [text]="true" [raised]="true"
|
||||||
class="p-button-rounded p-button-text"
|
class="p-button-rounded p-button-text"
|
||||||
(onClick)="actionClick(user.id,$event)"></p-button>
|
(onClick)="actionClick(user.id,$event)"></p-button>
|
||||||
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-table>
|
</p-table>
|
||||||
<p-menu #rowmenu [model]="items" [popup]="true" (onShow)="onMenuShow()" />
|
<p-menu #rowmenu [model]="items" [popup]="true" (onShow)="onMenuShow()" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+359
-359
@@ -1,359 +1,359 @@
|
|||||||
import { Component, OnInit, OnDestroy, inject, ChangeDetectorRef, signal, ViewChild} from '@angular/core';
|
import { Component, OnInit, OnDestroy, inject, ChangeDetectorRef, signal, ViewChild} from '@angular/core';
|
||||||
|
|
||||||
import { StaffView ,StaffSearch, Person } from '../models';
|
import { StaffView ,StaffSearch, Person } from '../models';
|
||||||
|
|
||||||
|
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { PersonService } from './person.service';
|
import { PersonService } from './person.service';
|
||||||
import { AuthenticationService } from '../user-services';
|
import { AuthenticationService } from '../user-services';
|
||||||
import { Table, TableModule } from 'primeng/table';
|
import { Table, TableModule } from '@openng/optimus-ui/table';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { ButtonModule } from 'primeng/button';
|
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||||
import { InputTextModule } from 'primeng/inputtext';
|
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||||
import { DialogService } from 'primeng/dynamicdialog';
|
import { DialogService } from '@openng/optimus-ui/dynamicdialog';
|
||||||
import { PersonEdit } from './person.edit';
|
import { PersonEdit } from './person.edit';
|
||||||
import { ConfirmationService, MenuItem, MessageService } from 'primeng/api';
|
import { ConfirmationService, MenuItem, MessageService } from '@openng/optimus-ui/api';
|
||||||
import { IconFieldModule } from 'primeng/iconfield';
|
import { IconFieldModule } from '@openng/optimus-ui/iconfield';
|
||||||
import { InputIconModule } from 'primeng/inputicon';
|
import { InputIconModule } from '@openng/optimus-ui/inputicon';
|
||||||
import { Menu, MenuModule } from 'primeng/menu';
|
import { Menu, MenuModule } from '@openng/optimus-ui/menu';
|
||||||
import { FamilyOrga } from './family.orga';
|
import { FamilyOrga } from './family.orga';
|
||||||
|
|
||||||
import { saveAs } from 'file-saver';
|
import { saveAs } from 'file-saver';
|
||||||
import * as XLSX from 'xlsx';
|
import * as XLSX from 'xlsx';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'family-list',
|
selector: 'family-list',
|
||||||
templateUrl: './familylist.html',
|
templateUrl: './familylist.html',
|
||||||
imports:[TableModule,FormsModule,CommonModule,ButtonModule,MenuModule,
|
imports:[TableModule,FormsModule,CommonModule,ButtonModule,MenuModule,
|
||||||
InputTextModule,IconFieldModule,InputIconModule],
|
InputTextModule,IconFieldModule,InputIconModule],
|
||||||
styleUrls: ['./familylist.css'],
|
styleUrls: ['./familylist.css'],
|
||||||
providers: [DialogService]
|
providers: [DialogService]
|
||||||
})
|
})
|
||||||
export class FamilyList implements OnInit, OnDestroy{
|
export class FamilyList implements OnInit, OnDestroy{
|
||||||
|
|
||||||
private subscription:Subscription = new Subscription();
|
private subscription:Subscription = new Subscription();
|
||||||
//private cd = inject(ChangeDetectorRef);
|
//private cd = inject(ChangeDetectorRef);
|
||||||
items: MenuItem[] | undefined;
|
items: MenuItem[] | undefined;
|
||||||
selectedPerson!: Person;
|
selectedPerson!: Person;
|
||||||
firstname = '';
|
firstname = '';
|
||||||
email = '';
|
email = '';
|
||||||
lastname = '';
|
lastname = '';
|
||||||
_id = -10;
|
_id = -10;
|
||||||
selectId = -1;
|
selectId = -1;
|
||||||
loading = false;
|
loading = false;
|
||||||
familyList = signal<Person[]>([]);
|
familyList = signal<Person[]>([]);
|
||||||
msg ="[Person component]";
|
msg ="[Person component]";
|
||||||
@ViewChild(Table) dt2!: Table;
|
@ViewChild(Table) dt2!: Table;
|
||||||
@ViewChild('rowmenu') popMenu?: Menu;
|
@ViewChild('rowmenu') popMenu?: Menu;
|
||||||
private messageService = inject(MessageService);
|
private messageService = inject(MessageService);
|
||||||
public dialogService= inject( DialogService);
|
public dialogService= inject( DialogService);
|
||||||
private personService= inject( PersonService);
|
private personService= inject( PersonService);
|
||||||
private confirmationService = inject(ConfirmationService);
|
private confirmationService = inject(ConfirmationService);
|
||||||
private cdr = inject(ChangeDetectorRef);
|
private cdr = inject(ChangeDetectorRef);
|
||||||
private authenticationService= inject( AuthenticationService);
|
private authenticationService= inject( AuthenticationService);
|
||||||
private router= inject( Router);
|
private router= inject( Router);
|
||||||
|
|
||||||
getSearchCiteria(): StaffSearch {
|
getSearchCiteria(): StaffSearch {
|
||||||
let criteria:StaffSearch = {
|
let criteria:StaffSearch = {
|
||||||
email: this.email,
|
email: this.email,
|
||||||
firstName: this.firstname,
|
firstName: this.firstname,
|
||||||
lastName: this.lastname,
|
lastName: this.lastname,
|
||||||
};
|
};
|
||||||
console.log("get search citeria", criteria);
|
console.log("get search citeria", criteria);
|
||||||
return criteria;
|
return criteria;
|
||||||
|
|
||||||
}
|
}
|
||||||
initMenu(): void {
|
initMenu(): void {
|
||||||
this.items = [
|
this.items = [
|
||||||
{
|
{
|
||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
icon: 'pi pi-pencil',
|
icon: 'pi pi-pencil',
|
||||||
command: () => {
|
command: () => {
|
||||||
this.edit(this.selectId);
|
this.edit(this.selectId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
iconClass:'text-red-500',
|
iconClass:'text-red-500',
|
||||||
styleClass:'text-red-500',
|
styleClass:'text-red-500',
|
||||||
icon: 'pi pi-times',
|
icon: 'pi pi-times',
|
||||||
command: () => {
|
command: () => {
|
||||||
this.delete(this.selectId);
|
this.delete(this.selectId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Show Family',
|
label: 'Show Family',
|
||||||
icon: 'pi pi-sitemap',
|
icon: 'pi pi-sitemap',
|
||||||
command: () => {
|
command: () => {
|
||||||
this.showChildren(this.selectId);
|
this.showChildren(this.selectId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
exportExport() : void {
|
exportExport() : void {
|
||||||
this.ExcelExport(this.familyList(), 'family_export');
|
this.ExcelExport(this.familyList(), 'family_export');
|
||||||
}
|
}
|
||||||
|
|
||||||
ExcelExport(data: any, fileName:string) :void
|
ExcelExport(data: any, fileName:string) :void
|
||||||
{
|
{
|
||||||
const worksheet = XLSX.utils.json_to_sheet(data);
|
const worksheet = XLSX.utils.json_to_sheet(data);
|
||||||
const workbook = XLSX.utils.book_new();
|
const workbook = XLSX.utils.book_new();
|
||||||
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
|
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
|
||||||
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
|
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
|
||||||
const blob = new Blob([excelBuffer], { type: 'application/octet-stream' });
|
const blob = new Blob([excelBuffer], { type: 'application/octet-stream' });
|
||||||
saveAs(blob, `${fileName}.xlsx`);
|
saveAs(blob, `${fileName}.xlsx`);
|
||||||
}
|
}
|
||||||
|
|
||||||
actionClick(id: number, event:Event): void {
|
actionClick(id: number, event:Event): void {
|
||||||
// console.log("action edit "+ id);
|
// console.log("action edit "+ id);
|
||||||
this.selectId = id;
|
this.selectId = id;
|
||||||
this.popMenu!.toggle(event);
|
this.popMenu!.toggle(event);
|
||||||
}
|
}
|
||||||
showChildren(id: number): void {
|
showChildren(id: number): void {
|
||||||
console.log("show children of id", id);
|
console.log("show children of id", id);
|
||||||
this.showOrganise(id);
|
this.showOrganise(id);
|
||||||
|
|
||||||
}
|
}
|
||||||
handleInput(event: Event) {
|
handleInput(event: Event) {
|
||||||
const value = (event.target as HTMLInputElement).value;
|
const value = (event.target as HTMLInputElement).value;
|
||||||
this.dt2.filterGlobal(value, 'contains');
|
this.dt2.filterGlobal(value, 'contains');
|
||||||
}
|
}
|
||||||
canSearch():boolean {
|
canSearch():boolean {
|
||||||
let result = false;
|
let result = false;
|
||||||
result = this.email !== "";
|
result = this.email !== "";
|
||||||
result = result || this.lastname !== "";
|
result = result || this.lastname !== "";
|
||||||
result = result || this.firstname !== "";
|
result = result || this.firstname !== "";
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
onMenuShow(): void {
|
onMenuShow(): void {
|
||||||
console.log("this is show", this.selectedPerson);
|
console.log("this is show", this.selectedPerson);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void
|
ngOnInit(): void
|
||||||
{
|
{
|
||||||
this.initMenu();
|
this.initMenu();
|
||||||
this.authenticationService.isHome = false;
|
this.authenticationService.isHome = false;
|
||||||
this.authenticationService.isReport = false;
|
this.authenticationService.isReport = false;
|
||||||
const prev = this.personService.searchCriteria;
|
const prev = this.personService.searchCriteria;
|
||||||
let goload = true;
|
let goload = true;
|
||||||
if (prev.lastName !== '')
|
if (prev.lastName !== '')
|
||||||
{
|
{
|
||||||
this.lastname = prev.lastName;
|
this.lastname = prev.lastName;
|
||||||
goload = true;
|
goload = true;
|
||||||
}
|
}
|
||||||
if (prev.firstName !== '')
|
if (prev.firstName !== '')
|
||||||
{
|
{
|
||||||
this.firstname = prev.firstName;
|
this.firstname = prev.firstName;
|
||||||
goload = true;
|
goload = true;
|
||||||
}
|
}
|
||||||
if (prev.email !== '')
|
if (prev.email !== '')
|
||||||
{
|
{
|
||||||
this.email = prev.email;
|
this.email = prev.email;
|
||||||
goload = true;
|
goload = true;
|
||||||
}
|
}
|
||||||
if (goload)
|
if (goload)
|
||||||
{
|
{
|
||||||
this.search();
|
this.search();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getActive(active:boolean):string {
|
getActive(active:boolean):string {
|
||||||
let result = 'false-icon pi-times-circle';
|
let result = 'false-icon pi-times-circle';
|
||||||
if (active)
|
if (active)
|
||||||
result = 'true-icon pi-check-circle';
|
result = 'true-icon pi-check-circle';
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
search():void {
|
search():void {
|
||||||
const canSearch = true; // this.canSearch();
|
const canSearch = true; // this.canSearch();
|
||||||
if (canSearch)
|
if (canSearch)
|
||||||
{
|
{
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const criteria = this.getSearchCiteria();
|
const criteria = this.getSearchCiteria();
|
||||||
this.personService.searchCriteria = criteria;
|
this.personService.searchCriteria = criteria;
|
||||||
this.subscription.add(
|
this.subscription.add(
|
||||||
this.personService.searchPersons(criteria).subscribe( {
|
this.personService.searchPersons(criteria).subscribe( {
|
||||||
next: result => {
|
next: result => {
|
||||||
// console.log(this.msg + "search load Data", result);
|
// console.log(this.msg + "search load Data", result);
|
||||||
const familyList = result.data;
|
const familyList = result.data;
|
||||||
this.familyList.set(familyList);
|
this.familyList.set(familyList);
|
||||||
this.updateParent( this.familyList());
|
this.updateParent( this.familyList());
|
||||||
//this.familyList.set(familyList);
|
//this.familyList.set(familyList);
|
||||||
|
|
||||||
console.log("the person from load", this.familyList());
|
console.log("the person from load", this.familyList());
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.cdr.detectChanges();
|
this.cdr.detectChanges();
|
||||||
},
|
},
|
||||||
error: e => {
|
error: e => {
|
||||||
const message = e || e.message;
|
const message = e || e.message;
|
||||||
// this.toastr.error(message);
|
// this.toastr.error(message);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
console.log("error ", e);
|
console.log("error ", e);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getName(id:number): string
|
getName(id:number): string
|
||||||
{
|
{
|
||||||
let result ="";
|
let result ="";
|
||||||
const item = this.familyList().find(x => x.id == id);
|
const item = this.familyList().find(x => x.id == id);
|
||||||
if (item)
|
if (item)
|
||||||
result = item.lastName + " " + item.firstName;
|
result = item.lastName + " " + item.firstName;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
updateParent(list:Person[]):void {
|
updateParent(list:Person[]):void {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let item:Person;
|
let item:Person;
|
||||||
for (i = 0; i< list.length; i++)
|
for (i = 0; i< list.length; i++)
|
||||||
{
|
{
|
||||||
item = list[i];
|
item = list[i];
|
||||||
if (item.fatherId && item.fatherId > 0)
|
if (item.fatherId && item.fatherId > 0)
|
||||||
{
|
{
|
||||||
item.fatherName = this.getName(item.fatherId);
|
item.fatherName = this.getName(item.fatherId);
|
||||||
}
|
}
|
||||||
if (item.motherId && item.motherId > 0)
|
if (item.motherId && item.motherId > 0)
|
||||||
{
|
{
|
||||||
item.motherName = this.getName(item.motherId);
|
item.motherName = this.getName(item.motherId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(id: number): void {
|
delete(id: number): void {
|
||||||
this.confirmationService.confirm({
|
this.confirmationService.confirm({
|
||||||
|
|
||||||
message: 'Do you want to delete this record?',
|
message: 'Do you want to delete this record?',
|
||||||
header: 'Confirmation Delete',
|
header: 'Confirmation Delete',
|
||||||
icon: 'pi pi-info-circle',
|
icon: 'pi pi-info-circle',
|
||||||
rejectLabel: 'Cancel',
|
rejectLabel: 'Cancel',
|
||||||
rejectButtonProps: {
|
rejectButtonProps: {
|
||||||
label: 'Cancel',
|
label: 'Cancel',
|
||||||
severity: 'secondary',
|
severity: 'secondary',
|
||||||
outlined: true,
|
outlined: true,
|
||||||
},
|
},
|
||||||
acceptButtonProps: {
|
acceptButtonProps: {
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
severity: 'danger',
|
severity: 'danger',
|
||||||
},
|
},
|
||||||
|
|
||||||
accept: () => {
|
accept: () => {
|
||||||
this.deleteItem(id);
|
this.deleteItem(id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteItem(id: number): void {
|
deleteItem(id: number): void {
|
||||||
this.personService.deletePerson(id)
|
this.personService.deletePerson(id)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe({ next: result => {
|
.subscribe({ next: result => {
|
||||||
console.log(this.msg + " deleteItem success", result);
|
console.log(this.msg + " deleteItem success", result);
|
||||||
|
|
||||||
const nlist = this.familyList().filter(d => d.id !== id);
|
const nlist = this.familyList().filter(d => d.id !== id);
|
||||||
this.familyList.set(nlist);
|
this.familyList.set(nlist);
|
||||||
this.cdr.detectChanges();
|
this.cdr.detectChanges();
|
||||||
},
|
},
|
||||||
error: e => console.error(e)
|
error: e => console.error(e)
|
||||||
});
|
});
|
||||||
//console.log(this.msg + "click button to delete");
|
//console.log(this.msg + "click button to delete");
|
||||||
}
|
}
|
||||||
|
|
||||||
newFamily():void {
|
newFamily():void {
|
||||||
//console.log("add new employee");
|
//console.log("add new employee");
|
||||||
this.personService.parentList = this.familyList();
|
this.personService.parentList = this.familyList();
|
||||||
// this.router.navigate( ['/family/new'], { queryParams: {returnUrl:'/family' } });
|
// this.router.navigate( ['/family/new'], { queryParams: {returnUrl:'/family' } });
|
||||||
this.showEdit(this._id--);
|
this.showEdit(this._id--);
|
||||||
}
|
}
|
||||||
edit(id: number) : void {
|
edit(id: number) : void {
|
||||||
//console.log("edit family", id);
|
//console.log("edit family", id);
|
||||||
this.personService.parentList = this.familyList();
|
this.personService.parentList = this.familyList();
|
||||||
// this.router.navigate( ['/family/'+id], { queryParams: {returnUrl:'/family' } });
|
// this.router.navigate( ['/family/'+id], { queryParams: {returnUrl:'/family' } });
|
||||||
this.showEdit(id);
|
this.showEdit(id);
|
||||||
}
|
}
|
||||||
showEdit(id:number) {
|
showEdit(id:number) {
|
||||||
const ref = this.dialogService.open(PersonEdit, {
|
const ref = this.dialogService.open(PersonEdit, {
|
||||||
data: {
|
data: {
|
||||||
id,
|
id,
|
||||||
familyList: this.familyList(),
|
familyList: this.familyList(),
|
||||||
},
|
},
|
||||||
header: 'Person',
|
header: 'Person',
|
||||||
width: '80%',
|
width: '80%',
|
||||||
draggable: true,
|
draggable: true,
|
||||||
maximizable: true
|
maximizable: true
|
||||||
});
|
});
|
||||||
if (ref)
|
if (ref)
|
||||||
{
|
{
|
||||||
ref.onClose.subscribe((item: Person) => {
|
ref.onClose.subscribe((item: Person) => {
|
||||||
if (item) {
|
if (item) {
|
||||||
//console.log("after close ward edit", item);
|
//console.log("after close ward edit", item);
|
||||||
// this.messageService.add({severity:'success', summary: 'Save Family', detail: item.firstName!});
|
// this.messageService.add({severity:'success', summary: 'Save Family', detail: item.firstName!});
|
||||||
//update the current list
|
//update the current list
|
||||||
this.updateList(item);
|
this.updateList(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showOrganise(id:number) {
|
showOrganise(id:number) {
|
||||||
const ref = this.dialogService.open(FamilyOrga, {
|
const ref = this.dialogService.open(FamilyOrga, {
|
||||||
data: {
|
data: {
|
||||||
id,
|
id,
|
||||||
familyList: this.familyList(),
|
familyList: this.familyList(),
|
||||||
},
|
},
|
||||||
header: 'Family Tree and Children',
|
header: 'Family Tree and Children',
|
||||||
width: '80%',
|
width: '80%',
|
||||||
maximizable: true,
|
maximizable: true,
|
||||||
closable: true
|
closable: true
|
||||||
});
|
});
|
||||||
if (ref)
|
if (ref)
|
||||||
{
|
{
|
||||||
ref.onClose.subscribe((item: Person) => {
|
ref.onClose.subscribe((item: Person) => {
|
||||||
if (item) {
|
if (item) {
|
||||||
//console.log("after close ward edit", item);
|
//console.log("after close ward edit", item);
|
||||||
// this.messageService.add({severity:'success', summary: 'Save Family', detail: item.firstName!});
|
// this.messageService.add({severity:'success', summary: 'Save Family', detail: item.firstName!});
|
||||||
//update the current list
|
//update the current list
|
||||||
//this.updateList(item);
|
//this.updateList(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateList(item: Person) :void {
|
updateList(item: Person) :void {
|
||||||
const list = this.familyList();
|
const list = this.familyList();
|
||||||
const idx = list.findIndex( x => x.id === item.id);
|
const idx = list.findIndex( x => x.id === item.id);
|
||||||
if (item.fatherId && item.fatherId > 0)
|
if (item.fatherId && item.fatherId > 0)
|
||||||
item.fatherName = this.getName(item.fatherId);
|
item.fatherName = this.getName(item.fatherId);
|
||||||
if (item.motherId && item.motherId > 0)
|
if (item.motherId && item.motherId > 0)
|
||||||
item.motherName = this.getName(item.motherId);
|
item.motherName = this.getName(item.motherId);
|
||||||
if (idx < 0)
|
if (idx < 0)
|
||||||
{
|
{
|
||||||
const olist = [... list, item];
|
const olist = [... list, item];
|
||||||
this.familyList.set(olist);
|
this.familyList.set(olist);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
const oitem = list[idx];
|
const oitem = list[idx];
|
||||||
oitem.firstName = item.firstName;
|
oitem.firstName = item.firstName;
|
||||||
oitem.lastName = item.lastName;
|
oitem.lastName = item.lastName;
|
||||||
oitem.address = item.address;
|
oitem.address = item.address;
|
||||||
oitem.alive = item.alive;
|
oitem.alive = item.alive;
|
||||||
oitem.dob = item.dob;
|
oitem.dob = item.dob;
|
||||||
oitem.sex = item.sex;
|
oitem.sex = item.sex;
|
||||||
oitem.email = item.email;
|
oitem.email = item.email;
|
||||||
oitem.fatherId = item.fatherId;
|
oitem.fatherId = item.fatherId;
|
||||||
oitem.motherId = item.motherId;
|
oitem.motherId = item.motherId;
|
||||||
oitem.fatherName = item.fatherName;
|
oitem.fatherName = item.fatherName;
|
||||||
oitem.motherName = item.motherName;
|
oitem.motherName = item.motherName;
|
||||||
this.familyList.set(list);
|
this.familyList.set(list);
|
||||||
}
|
}
|
||||||
this.cdr.markForCheck();
|
this.cdr.markForCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.subscription.unsubscribe();
|
this.subscription.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export * from './familylist';
|
export * from './familylist';
|
||||||
export * from './person.edit';
|
export * from './person.edit';
|
||||||
export * from './family.tree';
|
export * from './family.tree';
|
||||||
export * from './person.service';
|
export * from './person.service';
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
.profilePhotoBorder
|
.profilePhotoBorder
|
||||||
{
|
{
|
||||||
|
|
||||||
border-color: gray;
|
border-color: gray;
|
||||||
border-width: 2px;
|
border-width: 2px;
|
||||||
border-radius: 15%;
|
border-radius: 15%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profilePhotoWH
|
.profilePhotoWH
|
||||||
{
|
{
|
||||||
width: 150px;
|
width: 150px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
}
|
}
|
||||||
+133
-133
@@ -1,134 +1,134 @@
|
|||||||
<div class=" mt-2">
|
<div class=" mt-2">
|
||||||
|
|
||||||
<form [formGroup]="adminuserForm" (ngSubmit)="onSubmit($event)" >
|
<form [formGroup]="adminuserForm" (ngSubmit)="onSubmit($event)" >
|
||||||
<div class="ml-2 grid md:grid-cols-2 gap-3 p-2">
|
<div class="ml-2 grid md:grid-cols-2 gap-3 p-2">
|
||||||
<div>
|
<div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="lastname1">Surname<strong class="app-require">*</strong></label>
|
<label for="lastname1">Surname<strong class="app-require">*</strong></label>
|
||||||
<input id="lastname1" pInputText formControlName="lastname" type="text" [pAutoFocus]="true"
|
<input id="lastname1" pInputText formControlName="lastname" type="text" [pAutoFocus]="true"
|
||||||
[class]="getClassForRequire('inputfield w-full p-inputtext-sm','lastname')">
|
[class]="getClassForRequire('inputfield w-full p-inputtext-sm','lastname')">
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="firstname">First Name<strong class="app-require">*</strong></label>
|
<label for="firstname">First Name<strong class="app-require">*</strong></label>
|
||||||
<input id="firstname" pInputText formControlName="firstname" type="text"
|
<input id="firstname" pInputText formControlName="firstname" type="text"
|
||||||
[class]="getClassForRequire('inputfield w-full p-inputtext-sm','firstname')">
|
[class]="getClassForRequire('inputfield w-full p-inputtext-sm','firstname')">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--put here photo of person-->
|
<!--put here photo of person-->
|
||||||
<div class="flex flex-row gap-2">
|
<div class="flex flex-row gap-2">
|
||||||
<div>
|
<div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="dob" class="flex w-full">DOB</label>
|
<label for="dob" class="flex w-full">DOB</label>
|
||||||
<p-datepicker ariaLabelledBy="dob" formControlName="dob" [iconDisplay]="'input'" [showIcon]="true"
|
<p-datepicker ariaLabelledBy="dob" formControlName="dob" [iconDisplay]="'input'" [showIcon]="true"
|
||||||
dateFormat="dd/mm/yy" ></p-datepicker>
|
dateFormat="dd/mm/yy" ></p-datepicker>
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label class="flex w-full">Sex <strong class="app-require">*</strong></label>
|
<label class="flex w-full">Sex <strong class="app-require">*</strong></label>
|
||||||
<p-select [options]="sexList" optionLabel="name" optionValue="status" placeholder="Select Gender"
|
<p-select [options]="sexList" optionLabel="name" optionValue="status" placeholder="Select Gender"
|
||||||
formControlName="sex"
|
formControlName="sex"
|
||||||
[class]="getClassForRequire('inputfield w-full p-inputtext-sm','sex')"
|
[class]="getClassForRequire('inputfield w-full p-inputtext-sm','sex')"
|
||||||
class="w-full p-inputtext-sm mr-1"></p-select >
|
class="w-full p-inputtext-sm mr-1"></p-select >
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row shadow-md rounded-xl border-gray-100 border-1 p-4">
|
<div class="flex flex-row shadow-md rounded-xl border-gray-100 border-1 p-4">
|
||||||
<!--a href="{{hostsite}}/{{adminuserForm.value.image}}" target="_blank" class="text-blue-400">View Attachment
|
<!--a href="{{hostsite}}/{{adminuserForm.value.image}}" target="_blank" class="text-blue-400">View Attachment
|
||||||
</a-->
|
</a-->
|
||||||
<input type="file" class="file-input hidden" (change)="onFileSelected($event)" #fileUpload>
|
<input type="file" class="file-input hidden" (change)="onFileSelected($event)" #fileUpload>
|
||||||
@if (adminuserForm.value.image != "" && adminuserForm.value.image != null)
|
@if (adminuserForm.value.image != "" && adminuserForm.value.image != null)
|
||||||
{
|
{
|
||||||
<img id="blah" [src]= "dislayImage()" alt="your image"
|
<img id="blah" [src]= "dislayImage()" alt="your image"
|
||||||
class="profilePhotoWH profilePhotoBorder" (click)="doViewImage(adminuserForm.value.image)" />
|
class="profilePhotoWH profilePhotoBorder" (click)="doViewImage(adminuserForm.value.image)" />
|
||||||
|
|
||||||
}
|
}
|
||||||
@else
|
@else
|
||||||
{
|
{
|
||||||
<div class="file-upload profilePhotoBorder profilePhotoWH text-center flex justify-center items-center ">
|
<div class="file-upload profilePhotoBorder profilePhotoWH text-center flex justify-center items-center ">
|
||||||
<label class="">{{ adminuserForm.value.image || "No Profile Photo."}}</label>
|
<label class="">{{ adminuserForm.value.image || "No Profile Photo."}}</label>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
@if (adminuserForm.value.image != "" && adminuserForm.value.image != null)
|
@if (adminuserForm.value.image != "" && adminuserForm.value.image != null)
|
||||||
{
|
{
|
||||||
<button pButton type="button" icon="pi pi-times" pTooltip="remove profile photo"
|
<button pButton type="button" icon="pi pi-times" pTooltip="remove profile photo"
|
||||||
class="p-button-rounded p-button-text text-red-500 p-button-raised ml-2"
|
class="p-button-rounded p-button-text text-red-500 p-button-raised ml-2"
|
||||||
(click)="deleteFile()"></button>
|
(click)="deleteFile()"></button>
|
||||||
}
|
}
|
||||||
<button pButton type="button" icon="pi pi-paperclip"
|
<button pButton type="button" icon="pi pi-paperclip"
|
||||||
class="self-end p-button-rounded p-button-text p-button-raised ml-2" pTooltip="load photo"
|
class="self-end p-button-rounded p-button-text p-button-raised ml-2" pTooltip="load photo"
|
||||||
(click)="fileUpload.click()"></button>
|
(click)="fileUpload.click()"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!---->
|
<!---->
|
||||||
|
|
||||||
|
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="login">Email</label>
|
<label for="login">Email</label>
|
||||||
<input id="login" [attr.disabled]="!isNew?true:null" pInputText formControlName="email"
|
<input id="login" [attr.disabled]="!isNew?true:null" pInputText formControlName="email"
|
||||||
type="text" class="inputfield w-full">
|
type="text" class="inputfield w-full">
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="phone" class="w-full">Phone</label>
|
<label for="phone" class="w-full">Phone</label>
|
||||||
<input class="w-full" id="phone" pInputText formControlName="phone" type="text" >
|
<input class="w-full" id="phone" pInputText formControlName="phone" type="text" >
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label class="flex w-full">Father</label>
|
<label class="flex w-full">Father</label>
|
||||||
<p-select [filter]="true" [showClear]="true" filterBy="name" [options]="fatherList" optionLabel="name" appendTo="body" optionValue="id" placeholder="Select Parent"
|
<p-select [filter]="true" [showClear]="true" filterBy="name" [options]="fatherList" optionLabel="name" appendTo="body" optionValue="id" placeholder="Select Parent"
|
||||||
formControlName="fatherId" class="w-full p-inputtext-sm mr-1"></p-select >
|
formControlName="fatherId" class="w-full p-inputtext-sm mr-1"></p-select >
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label class="flex w-full">Mother</label>
|
<label class="flex w-full">Mother</label>
|
||||||
<p-select [options]="motherList" [showClear]="true" [filter]="true" filterBy="name" optionLabel="name" appendTo="body" optionValue="id" placeholder="Select Parent"
|
<p-select [options]="motherList" [showClear]="true" [filter]="true" filterBy="name" optionLabel="name" appendTo="body" optionValue="id" placeholder="Select Parent"
|
||||||
formControlName="motherId" class="w-full p-inputtext-sm mr-1"></p-select >
|
formControlName="motherId" class="w-full p-inputtext-sm mr-1"></p-select >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid align-end">
|
<div class="grid align-end">
|
||||||
<div class="p-field-checkbox">
|
<div class="p-field-checkbox">
|
||||||
<p-checkbox inputId="alive" formControlName="alive" [binary]="true"></p-checkbox>
|
<p-checkbox inputId="alive" formControlName="alive" [binary]="true"></p-checkbox>
|
||||||
<label for="alive" class="ml-2 w-full">Alive</label>
|
<label for="alive" class="ml-2 w-full">Alive</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2 w-full">
|
<div class="mt-2 w-full">
|
||||||
<div class="flex flex-row justify-between">
|
<div class="flex flex-row justify-between">
|
||||||
<p-button icon="pi pi-images" [raised]="true"
|
<p-button icon="pi pi-images" [raised]="true"
|
||||||
badge="{{photoList.length}}"
|
badge="{{photoList.length}}"
|
||||||
severity="success" label="Attach Photos"
|
severity="success" label="Attach Photos"
|
||||||
(onClick)="viewAttachment()"/>
|
(onClick)="viewAttachment()"/>
|
||||||
<p-button icon="pi pi-user" [raised]="true" severity="info" label="Add Partner"
|
<p-button icon="pi pi-user" [raised]="true" severity="info" label="Add Partner"
|
||||||
(onClick)="addPartner()"/>
|
(onClick)="addPartner()"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="shadow rounded mt-2 mb-2">
|
<div class="shadow rounded mt-2 mb-2">
|
||||||
<p-table [value]="partners()">
|
<p-table [value]="partners()">
|
||||||
<ng-template #header>
|
<ng-template #header>
|
||||||
<tr>
|
<tr>
|
||||||
<th>First Name</th>
|
<th>First Name</th>
|
||||||
<th>Last Name</th>
|
<th>Last Name</th>
|
||||||
<th>Sex</th>
|
<th>Sex</th>
|
||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template #body let-user>
|
<ng-template #body let-user>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ user.pfirstName }}</td>
|
<td>{{ user.pfirstName }}</td>
|
||||||
<td>{{ user.plastName }}</td>
|
<td>{{ user.plastName }}</td>
|
||||||
<td>{{ user.sex }}</td>
|
<td>{{ user.sex }}</td>
|
||||||
<td>
|
<td>
|
||||||
<button pButton type="button" icon="pi pi-times" class="p-button-rounded p-button-text p-button-danger"
|
<button pButton type="button" icon="pi pi-times" class="p-button-rounded p-button-text p-button-danger"
|
||||||
(click)="onDeletePartner(user)"></button>
|
(click)="onDeletePartner(user)"></button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-table>
|
</p-table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end mr-2 mb-2 p-2">
|
<div class="flex justify-end mr-2 mb-2 p-2">
|
||||||
<button pButton type="submit" class="p-button-sm mr-2" icon="pi pi-check" label="Save" [disabled]="isFieldsChange"></button>
|
<button pButton type="submit" class="p-button-sm mr-2" icon="pi pi-check" label="Save" [disabled]="isFieldsChange"></button>
|
||||||
<button pButton pRipple class="p-button-sm p-button-secondary" type="button" icon="pi pi-times" label="Cancel" (click)="cancel($event)"></button>
|
<button pButton pRipple class="p-button-sm p-button-secondary" type="button" icon="pi pi-times" label="Cancel" (click)="cancel($event)"></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<!--pre>{{ adminuserForm.value|json}}</pre-->
|
<!--pre>{{ adminuserForm.value|json}}</pre-->
|
||||||
</div>
|
</div>
|
||||||
+771
-764
File diff suppressed because it is too large
Load Diff
+136
-109
@@ -1,109 +1,136 @@
|
|||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { Staff,StaffSearch, StaffView, ResultModel,ConfigureUrl,ResetPassword, Person, PersonContainer, RelationShip } from '../models';
|
import { Staff,StaffSearch, StaffView, ResultModel,ConfigureUrl,ResetPassword, Person, PersonContainer, RelationShip } from '../models';
|
||||||
import { AppSettingService } from '../shares';
|
import { AppSettingService } from '../shares';
|
||||||
import { TreeNode } from 'primeng/api';
|
import { TreeNode } from '@openng/optimus-ui/api';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class PersonService {
|
export class PersonService {
|
||||||
public searchCriteria: StaffSearch;
|
public searchCriteria: StaffSearch;
|
||||||
public parentList: Person[] =[];
|
public parentList: Person[] =[];
|
||||||
constructor(private http: HttpClient,
|
constructor(private http: HttpClient,
|
||||||
|
|
||||||
private appSetting :AppSettingService
|
private appSetting :AppSettingService
|
||||||
) {
|
) {
|
||||||
this.searchCriteria = {
|
this.searchCriteria = {
|
||||||
email:'',
|
email:'',
|
||||||
firstName: '',
|
firstName: '',
|
||||||
lastName:''
|
lastName:''
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
searchPersons(criteria: StaffSearch): Observable<ResultModel<Person[]>> {
|
searchPersons(criteria: StaffSearch): Observable<ResultModel<Person[]>> {
|
||||||
let config = { headers : { 'Content-Type': 'application/json' } };
|
let config = { headers : { 'Content-Type': 'application/json' } };
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl + "/SearchPerson";
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl + "/SearchPerson";
|
||||||
return this.http.post<ResultModel<Person[]>>(baseUrl, criteria, config);
|
return this.http.post<ResultModel<Person[]>>(baseUrl, criteria, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPersonById(id:number): Observable<ResultModel<Person>> {
|
loadPersonById(id:number): Observable<ResultModel<Person>> {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl;
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl;
|
||||||
/*
|
/*
|
||||||
const params = new HttpParams().set("id", ""+id);
|
const params = new HttpParams().set("id", ""+id);
|
||||||
const headers = new HttpHeaders().set('Content-Type', 'application/json');
|
const headers = new HttpHeaders().set('Content-Type', 'application/json');
|
||||||
const options = {
|
const options = {
|
||||||
headers: headers,
|
headers: headers,
|
||||||
params: params
|
params: params
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return this.http.get<ResultModel<Person>>(baseUrl + "/GetById/" + id);
|
return this.http.get<ResultModel<Person>>(baseUrl + "/GetById/" + id);
|
||||||
}
|
}
|
||||||
loadPersonFamily(id: number): Observable<ResultModel<TreeNode>> {
|
loadPersonFamily(id: number): Observable<ResultModel<TreeNode>> {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl;
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl;
|
||||||
return this.http.get<ResultModel<TreeNode>>(baseUrl + "/GetByPersonFamily/" + id);
|
return this.http.get<ResultModel<TreeNode>>(baseUrl + "/GetByPersonFamily/" + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPersonFamilyTree(useFather: boolean, useMother: boolean): Observable<ResultModel<TreeNode[]>> {
|
loadPersonFamilyTree(useFather: boolean, useMother: boolean): Observable<ResultModel<TreeNode[]>> {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl;
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl;
|
||||||
const data = {useFather,useMother};
|
const data = {useFather,useMother};
|
||||||
return this.http.post<ResultModel<TreeNode[]>>(baseUrl + "/GetFamilyTreeBy", data);
|
return this.http.post<ResultModel<TreeNode[]>>(baseUrl + "/GetFamilyTreeBy", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadChildrenById(fatherId:number, motherId: number): Observable<ResultModel<Person[]>> {
|
loadChildrenById(fatherId:number, motherId: number): Observable<ResultModel<Person[]>> {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl;
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl;
|
||||||
const data = {fatherId,motherId};
|
const data = {fatherId,motherId};
|
||||||
|
|
||||||
return this.http.post<ResultModel<Person[]>>(baseUrl + "/GetChildress/" ,data);
|
return this.http.post<ResultModel<Person[]>>(baseUrl + "/GetChildress/" ,data);
|
||||||
}
|
}
|
||||||
loadRelationshipById(personId:number): Observable<ResultModel<RelationShip[]>> {
|
loadRelationshipById(personId:number): Observable<ResultModel<RelationShip[]>> {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.relationShipUrl;
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.relationShipUrl;
|
||||||
return this.http.get<ResultModel<RelationShip[]>>(baseUrl + "/GetByPersonId/" +personId);
|
return this.http.get<ResultModel<RelationShip[]>>(baseUrl + "/GetByPersonId/" +personId);
|
||||||
}
|
}
|
||||||
savePerson(data:PersonContainer): Observable<ResultModel<number>> { //insert Adminuser
|
savePerson(data:PersonContainer): Observable<ResultModel<number>> { //insert Adminuser
|
||||||
let config = { headers : { 'Content-Type': 'application/json' } };
|
let config = { headers : { 'Content-Type': 'application/json' } };
|
||||||
console.log("save family", data);
|
console.log("save family", data);
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl +"/SavePerson";
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl +"/SavePerson";
|
||||||
return this.http.post<ResultModel<number>>(baseUrl, data, config);
|
return this.http.post<ResultModel<number>>(baseUrl, data, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
deletePerson(id:number): Observable<ResultModel<number>>{
|
deletePerson(id:number): Observable<ResultModel<number>>{
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl;
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.personUrl;
|
||||||
const data = {id};
|
const data = {id};
|
||||||
return this.http.post<ResultModel<number>>(baseUrl + "/DeleteById" ,data);
|
return this.http.post<ResultModel<number>>(baseUrl + "/DeleteById" ,data);
|
||||||
}
|
}
|
||||||
uploadFile(data: any): Observable<ResultModel<string>> {
|
uploadFile(data: any): Observable<ResultModel<string>> {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.personUrl + "/UploadImage";
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.personUrl + "/UploadImage";
|
||||||
return this.http.post<ResultModel<string>>(baseUrl, data);
|
return this.http.post<ResultModel<string>>(baseUrl, data);
|
||||||
}
|
}
|
||||||
downloadFile(imageName: string): Observable<ResultModel<string>> {
|
downloadFile_dontusethis(imageName: string, personId: number,
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DownloadFile";
|
photoType: number): Observable<ResultModel<string>> {
|
||||||
const data = {
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DownloadFile";
|
||||||
fileName: imageName
|
const data = {
|
||||||
};
|
fileName: imageName,
|
||||||
return this.http.post<ResultModel<string>>(baseUrl, data);
|
id: personId,
|
||||||
}
|
photoType
|
||||||
deleteUploadFile(data: any): Observable<ResultModel<number>> {
|
};
|
||||||
//data ={filename};
|
return this.http.post<ResultModel<string>>(baseUrl, data);
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.personUrl + "/DeleteUploadFile";
|
}
|
||||||
return this.http.post<ResultModel<number>>(baseUrl, data);
|
deleteUploadFile_dotnotuse(data: any): Observable<ResultModel<number>> {
|
||||||
}
|
//data ={filename};
|
||||||
deletePersonPhotoFile(id: number): Observable<ResultModel<number>> {
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.personUrl + "/DeleteUploadFile";
|
||||||
const data ={id, fileName:''};
|
return this.http.post<ResultModel<number>>(baseUrl, data);
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DeletePersonPhoto";
|
}
|
||||||
return this.http.post<ResultModel<number>>(baseUrl, data);
|
deletePersonPhotoFile(personId: number, photoType: number): Observable<ResultModel<number>> {
|
||||||
}
|
const data = {
|
||||||
savePersonPhotoList(data:FormData): Observable<ResultModel<number>> {
|
id: personId,
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/SavePersonPhoto";
|
fileName: '',
|
||||||
return this.http.post<ResultModel<number>>(baseUrl, data);
|
photoType
|
||||||
}
|
};
|
||||||
downloadPersonPhoto(id: number): Observable<ResultModel<string>> {
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DeletePersonPhoto";
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DownloadPersonPhoto";
|
return this.http.post<ResultModel<number>>(baseUrl, data);
|
||||||
const data = {
|
}
|
||||||
id,
|
deletePersonPhotoFileById(id: number): Observable<ResultModel<number>> {
|
||||||
fileName: ''
|
const data = {
|
||||||
};
|
id
|
||||||
return this.http.post<ResultModel<string>>(baseUrl, data);
|
};
|
||||||
}
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DeletePersonPhotoById";
|
||||||
}
|
return this.http.post<ResultModel<number>>(baseUrl, data);
|
||||||
|
}
|
||||||
|
savePersonPhotoList(data:FormData): Observable<ResultModel<number>> {
|
||||||
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/SavePersonPhoto";
|
||||||
|
return this.http.post<ResultModel<number>>(baseUrl, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadPersonPhoto64(imageName: string, personId: number,
|
||||||
|
photoType: number): Observable<ResultModel<string>> {
|
||||||
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DownloadPersonPhoto64";
|
||||||
|
const data = {
|
||||||
|
id: personId,
|
||||||
|
photoType,
|
||||||
|
fileName: imageName
|
||||||
|
};
|
||||||
|
return this.http.post<ResultModel<string>>(baseUrl, data);
|
||||||
|
}
|
||||||
|
downloadPersonPhoto(imageName: string, personId: number,
|
||||||
|
photoType: number): Observable<any> {
|
||||||
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/" + ConfigureUrl.FileUploadUrl + "/DownloadPersonPhoto";
|
||||||
|
const data = {
|
||||||
|
id: personId,
|
||||||
|
photoType,
|
||||||
|
fileName: imageName
|
||||||
|
};
|
||||||
|
return this.http.post<any>(baseUrl, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<img [src]="imageDataUrl()" alt="Person Image" width="400" height="300"/>
|
<img [src]="imageDataUrl()" alt="Person Image" width="400" height="300"/>
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<button pButton pRipple class="p-button-sm mr-2 p-button-secondary" type="button" icon="pi pi-sign-in" label="Close"
|
<button pButton pRipple class="p-button-sm mr-2 p-button-secondary" type="button" icon="pi pi-sign-in" label="Close"
|
||||||
(click)="close()"></button>
|
(click)="close()"></button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,64 +1,66 @@
|
|||||||
import { Component, inject, OnDestroy, OnInit, signal } from '@angular/core';
|
import { Component, inject, OnDestroy, OnInit, signal } from '@angular/core';
|
||||||
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
||||||
import { AppSettingService } from '../shares';
|
import { AppSettingService } from '../shares';
|
||||||
import { PersonService } from '../person';
|
import { PersonService } from '../person';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { ButtonModule } from 'primeng/button';
|
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||||
import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
|
import { DynamicDialogConfig, DynamicDialogRef } from '@openng/optimus-ui/dynamicdialog';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-image-display',
|
selector: 'app-image-display',
|
||||||
imports:[CommonModule, ButtonModule],
|
imports:[CommonModule, ButtonModule],
|
||||||
templateUrl: './image.display.html',
|
templateUrl: './image.display.html',
|
||||||
styleUrls: ['./image.display.css']
|
styleUrls: ['./image.display.css']
|
||||||
})
|
})
|
||||||
export class ImageDisplayComponent implements OnInit, OnDestroy {
|
export class ImageDisplayComponent implements OnInit, OnDestroy {
|
||||||
//base64ImageString: string = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='; // Example Base64 (a tiny red dot PNG)
|
//base64ImageString: string = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='; // Example Base64 (a tiny red dot PNG)
|
||||||
//imageDataUrl: SafeResourceUrl ={};
|
//imageDataUrl: SafeResourceUrl ={};
|
||||||
imageDataUrl = signal<string>("");
|
imageDataUrl = signal<string>("");
|
||||||
private personService = inject(PersonService);
|
private personService = inject(PersonService);
|
||||||
private sanitizer = inject(DomSanitizer);
|
private sanitizer = inject(DomSanitizer);
|
||||||
//private route = inject(ActivatedRoute);
|
//private route = inject(ActivatedRoute);
|
||||||
public ref = inject(DynamicDialogRef);
|
public ref = inject(DynamicDialogRef);
|
||||||
public config = inject(DynamicDialogConfig);
|
public config = inject(DynamicDialogConfig);
|
||||||
private subscription:Subscription = new Subscription();
|
private subscription:Subscription = new Subscription();
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
||||||
const imageName = this.config.data.imageName;
|
const imageName = this.config.data.imageName;
|
||||||
this.loadImage(imageName);
|
const personId = this.config.data.personId;
|
||||||
|
const photoType = this.config.data.photyType;
|
||||||
}
|
this.loadImage(imageName, personId, photoType);
|
||||||
loadImage(fileName: string| null): void {
|
|
||||||
const download = this.personService.downloadFile(fileName!);
|
}
|
||||||
this.subscription.add(download.subscribe({
|
loadImage(fileName: string | null, personId: number, photoType: number): void {
|
||||||
next: x => {
|
const download = this.personService.downloadPersonPhoto64(fileName!, personId, photoType);
|
||||||
if (x.statusCode == 1)
|
this.subscription.add(download.subscribe({
|
||||||
{
|
next: x => {
|
||||||
this.display(x.data);
|
if (x.statusCode == 1)
|
||||||
console.log("this is show image" , this.imageDataUrl(), x);
|
{
|
||||||
}
|
this.display(x.data);
|
||||||
else
|
console.log("this is show image" , this.imageDataUrl(), x);
|
||||||
{
|
}
|
||||||
console.log("error in download in api ", x.message);
|
else
|
||||||
}
|
{
|
||||||
},
|
console.log("error in download in api ", x.message);
|
||||||
error: e => console.error("error in download image", e)
|
}
|
||||||
}));
|
},
|
||||||
}
|
error: e => console.error("error in download image", e)
|
||||||
display(baseImage: string): void
|
}));
|
||||||
{
|
}
|
||||||
const changeUrl = (this.sanitizer.bypassSecurityTrustResourceUrl(baseImage) as any).changingThisBreaksApplicationSecurity;
|
display(baseImage: string): void
|
||||||
console.log('this is bypassSecurityTrustResourceUrl', changeUrl);
|
{
|
||||||
const fullDataUri = `data:image/png;base64,${changeUrl}`;
|
const changeUrl = (this.sanitizer.bypassSecurityTrustResourceUrl(baseImage) as any).changingThisBreaksApplicationSecurity;
|
||||||
this.imageDataUrl.set(fullDataUri);
|
console.log('this is bypassSecurityTrustResourceUrl', changeUrl);
|
||||||
}
|
const fullDataUri = `data:image/png;base64,${changeUrl}`;
|
||||||
ngOnDestroy(): void {
|
this.imageDataUrl.set(fullDataUri);
|
||||||
this.subscription.unsubscribe();
|
}
|
||||||
}
|
ngOnDestroy(): void {
|
||||||
close() :void {
|
this.subscription.unsubscribe();
|
||||||
this.ref.close(null);
|
}
|
||||||
}
|
close() :void {
|
||||||
|
this.ref.close(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,47 +1,47 @@
|
|||||||
<div class="flex-row w-full h-full">
|
<div class="flex-row w-full h-full">
|
||||||
<p-table #dt2 [value]="familyList()" sortMode="multiple"
|
<p-table #dt2 [value]="familyList()" sortMode="multiple"
|
||||||
class="p-datatable-sm" paginatorDropdownAppendTo="body"
|
class="p-datatable-sm" paginatorDropdownAppendTo="body"
|
||||||
dataKey="id" selectionMode="single" [(selection)]="selectedPerson"
|
dataKey="id" selectionMode="single" [(selection)]="selectedPerson"
|
||||||
[paginator]="true" [globalFilterFields]="['lastName', 'firstName', 'sex']"
|
[paginator]="true" [globalFilterFields]="['lastName', 'firstName', 'sex']"
|
||||||
[rows]="10" [rowsPerPageOptions]="[5,10, 20,50]"
|
[rows]="10" [rowsPerPageOptions]="[5,10, 20,50]"
|
||||||
[loading]="loading">
|
[loading]="loading">
|
||||||
<ng-template #caption>
|
<ng-template #caption>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<p-iconfield iconPosition="left" class="ml-auto">
|
<p-iconfield iconPosition="left" class="ml-auto">
|
||||||
<p-inputicon>
|
<p-inputicon>
|
||||||
<i class="pi pi-search"></i>
|
<i class="pi pi-search"></i>
|
||||||
</p-inputicon>
|
</p-inputicon>
|
||||||
<input pInputText type="text" (input)="handleInput($event)" placeholder="Search keyword" />
|
<input pInputText type="text" (input)="handleInput($event)" placeholder="Search keyword" />
|
||||||
</p-iconfield>
|
</p-iconfield>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template pTemplate="header">
|
<ng-template pTemplate="header">
|
||||||
<tr>
|
<tr>
|
||||||
<th pSortableColumn="lastName">Last Name <p-sortIcon field="lastName"></p-sortIcon>
|
<th pSortableColumn="lastName">Last Name <p-sortIcon field="lastName"></p-sortIcon>
|
||||||
</th>
|
</th>
|
||||||
<th pSortableColumn="firstName">First Name <p-sortIcon field="firstName"></p-sortIcon>
|
<th pSortableColumn="firstName">First Name <p-sortIcon field="firstName"></p-sortIcon>
|
||||||
</th>
|
</th>
|
||||||
<th pSortableColumn="sex">Sex<p-sortIcon field="sex"></p-sortIcon>
|
<th pSortableColumn="sex">Sex<p-sortIcon field="sex"></p-sortIcon>
|
||||||
</th>
|
</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template pTemplate="body" let-user>
|
<ng-template pTemplate="body" let-user>
|
||||||
<tr [pSelectableRow]="user">
|
<tr [pSelectableRow]="user">
|
||||||
<td>{{user.lastName}}</td>
|
<td>{{user.lastName}}</td>
|
||||||
<td>{{user.firstName}}</td>
|
<td>{{user.firstName}}</td>
|
||||||
<td>{{user.sex}}</td>
|
<td>{{user.sex}}</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-table>
|
</p-table>
|
||||||
<div class="flex justify-end mr-2 mb-2 p-2">
|
<div class="flex justify-end mr-2 mb-2 p-2">
|
||||||
<button pButton type="submit" class="p-button-sm mr-2"
|
<button pButton type="submit" class="p-button-sm mr-2"
|
||||||
icon="pi pi-check" iconPos="left" label="Select"
|
icon="pi pi-check" iconPos="left" label="Select"
|
||||||
(click)="select($event)" [disabled]="selectedPerson == null" ></button>
|
(click)="select($event)" [disabled]="selectedPerson == null" ></button>
|
||||||
<button pButton pRipple class="p-button-sm" type="button"
|
<button pButton pRipple class="p-button-sm" type="button"
|
||||||
icon="pi pi-times" iconPos="left"
|
icon="pi pi-times" iconPos="left"
|
||||||
label="Cancel" (click)="cancel($event)"></button>
|
label="Cancel" (click)="cancel($event)"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,53 +1,53 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Component, OnDestroy, OnInit, signal, ViewChild } from '@angular/core';
|
import { Component, OnDestroy, OnInit, signal, ViewChild } from '@angular/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { Table, TableModule } from 'primeng/table';
|
import { Table, TableModule } from '@openng/optimus-ui/table';
|
||||||
import { Person } from '../models';
|
import { Person } from '../models';
|
||||||
import { IconFieldModule } from 'primeng/iconfield';
|
import { IconFieldModule } from '@openng/optimus-ui/iconfield';
|
||||||
import { InputIconModule } from 'primeng/inputicon';
|
import { InputIconModule } from '@openng/optimus-ui/inputicon';
|
||||||
import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
|
import { DynamicDialogConfig, DynamicDialogRef } from '@openng/optimus-ui/dynamicdialog';
|
||||||
import { ButtonModule } from 'primeng/button';
|
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||||
import { InputTextModule } from 'primeng/inputtext';
|
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pickperson',
|
selector: 'app-pickperson',
|
||||||
imports: [TableModule, ButtonModule,CommonModule, InputTextModule, FormsModule,IconFieldModule,InputIconModule],
|
imports: [TableModule, ButtonModule,CommonModule, InputTextModule, FormsModule,IconFieldModule,InputIconModule],
|
||||||
templateUrl: './pickperson.html',
|
templateUrl: './pickperson.html',
|
||||||
styleUrl: './pickperson.css'
|
styleUrl: './pickperson.css'
|
||||||
})
|
})
|
||||||
export class Pickperson implements OnInit, OnDestroy{
|
export class Pickperson implements OnInit, OnDestroy{
|
||||||
@ViewChild(Table) dt2!: Table;
|
@ViewChild(Table) dt2!: Table;
|
||||||
constructor(public ref: DynamicDialogRef, public config: DynamicDialogConfig)
|
constructor(public ref: DynamicDialogRef, public config: DynamicDialogConfig)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
loading = false;
|
loading = false;
|
||||||
familyList = signal<Person[]>([]);
|
familyList = signal<Person[]>([]);
|
||||||
selectedPerson!: Person;
|
selectedPerson!: Person;
|
||||||
handleInput(event: Event) {
|
handleInput(event: Event) {
|
||||||
const value = (event.target as HTMLInputElement).value;
|
const value = (event.target as HTMLInputElement).value;
|
||||||
this.dt2.filterGlobal(value, 'contains');
|
this.dt2.filterGlobal(value, 'contains');
|
||||||
}
|
}
|
||||||
|
|
||||||
edit(id: number): void {
|
edit(id: number): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
cancel(e:Event):void {
|
cancel(e:Event):void {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.ref.close(null);
|
this.ref.close(null);
|
||||||
}
|
}
|
||||||
select(e:Event):void {
|
select(e:Event):void {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.ref.close(this.selectedPerson);
|
this.ref.close(this.selectedPerson);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
console.log("pick person the familyList", this.config);
|
console.log("pick person the familyList", this.config);
|
||||||
this.familyList.set(this.config.data.familyList);
|
this.familyList.set(this.config.data.familyList);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
import { Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||||
import { Utils } from '../shares';
|
import { Utils } from '../shares';
|
||||||
import {AuthenticationService} from '../user-services/authentication.service';
|
import {AuthenticationService} from '../user-services/authentication.service';
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class AuthGuard {
|
export class AuthGuard {
|
||||||
msg ="[AuthGuard] ";
|
msg ="[AuthGuard] ";
|
||||||
constructor(private router: Router,
|
constructor(private router: Router,
|
||||||
private authService :AuthenticationService ) { }
|
private authService :AuthenticationService ) { }
|
||||||
|
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
const roleAllowed = route.data['roleAllowed'];
|
const roleAllowed = route.data['roleAllowed'];
|
||||||
const user = Utils.getCurrentUser();
|
const user = Utils.getCurrentUser();
|
||||||
const userRole = Utils.getUserRole(user);
|
const userRole = Utils.getUserRole(user);
|
||||||
let hasLoggedIn = Utils.getIsAuth();
|
let hasLoggedIn = Utils.getIsAuth();
|
||||||
//console.log(this.msg + " the userlogin ", user, hasLoggedIn);
|
//console.log(this.msg + " the userlogin ", user, hasLoggedIn);
|
||||||
if (hasLoggedIn) {
|
if (hasLoggedIn) {
|
||||||
|
|
||||||
if (roleAllowed != undefined)
|
if (roleAllowed != undefined)
|
||||||
{
|
{
|
||||||
//it number toString
|
//it number toString
|
||||||
// console.log("[auth-guard] ther roleAllow ", roleAllowed);
|
// console.log("[auth-guard] ther roleAllow ", roleAllowed);
|
||||||
// console.log("[auth-guard] before roleAllow ", roleAllowed,userRole);
|
// console.log("[auth-guard] before roleAllow ", roleAllowed,userRole);
|
||||||
if (roleAllowed.indexOf(userRole.toString()) != -1) {
|
if (roleAllowed.indexOf(userRole.toString()) != -1) {
|
||||||
// console.log("[auth-guard] pass roleAllow ", roleAllowed,userRole);
|
// console.log("[auth-guard] pass roleAllow ", roleAllowed,userRole);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.authService.logout();
|
this.authService.logout();
|
||||||
this.router.navigate(['/login']);
|
this.router.navigate(['/login']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else //if no role define just return hasLoggedIn
|
else //if no role define just return hasLoggedIn
|
||||||
{
|
{
|
||||||
return hasLoggedIn;
|
return hasLoggedIn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// this.authService.logout();
|
// this.authService.logout();
|
||||||
this.router.navigate(['/login']);
|
this.router.navigate(['/login']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not logged in so redirect to login page with the return url
|
// not logged in so redirect to login page with the return url
|
||||||
//this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
|
//this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
|
||||||
this.authService.logout();
|
this.authService.logout();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export * from './auth.guard';
|
export * from './auth.guard';
|
||||||
|
|||||||
@@ -1,54 +1,54 @@
|
|||||||
import { FormControl, FormGroup } from '@angular/forms';
|
import { FormControl, FormGroup } from '@angular/forms';
|
||||||
|
|
||||||
export class CommonUtilities {
|
export class CommonUtilities {
|
||||||
/** Display the blob */
|
/** Display the blob */
|
||||||
static displayFileInNewTab(response:any, defaultFileName:string) {
|
static displayFileInNewTab(response:any, defaultFileName:string) {
|
||||||
const contentType = response.headers.get('content-type');
|
const contentType = response.headers.get('content-type');
|
||||||
const blob = new Blob([response.body], { type: contentType });
|
const blob = new Blob([response.body], { type: contentType });
|
||||||
const fileName = this.getFileName(response,defaultFileName);
|
const fileName = this.getFileName(response,defaultFileName);
|
||||||
const nav = (window.navigator as any);
|
const nav = (window.navigator as any);
|
||||||
if (nav.msSaveOrOpenBlob) {
|
if (nav.msSaveOrOpenBlob) {
|
||||||
nav.msSaveOrOpenBlob(blob, fileName);
|
nav.msSaveOrOpenBlob(blob, fileName);
|
||||||
} else {
|
} else {
|
||||||
const data = window.URL.createObjectURL(blob);
|
const data = window.URL.createObjectURL(blob);
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
link.href = data;
|
link.href = data;
|
||||||
link.target = '_blank';
|
link.target = '_blank';
|
||||||
link.click();
|
link.click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*** Download the blob ***/
|
/*** Download the blob ***/
|
||||||
static downloadFile(response:any, defaultFileName:string) {
|
static downloadFile(response:any, defaultFileName:string) {
|
||||||
const contentType = response.headers.get('content-type');
|
const contentType = response.headers.get('content-type');
|
||||||
const blob = new Blob([response.body], { type: contentType });
|
const blob = new Blob([response.body], { type: contentType });
|
||||||
const fileName = this.getFileName(response,defaultFileName);
|
const fileName = this.getFileName(response,defaultFileName);
|
||||||
const nav = (window.navigator as any);
|
const nav = (window.navigator as any);
|
||||||
if (typeof nav.msSaveBlob === 'function')
|
if (typeof nav.msSaveBlob === 'function')
|
||||||
{
|
{
|
||||||
console.log("download the report saveblob");
|
console.log("download the report saveblob");
|
||||||
nav.msSaveBlob(blob, fileName);
|
nav.msSaveBlob(blob, fileName);
|
||||||
console.log("download the report saveblob done");
|
console.log("download the report saveblob done");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
link.href = window.URL.createObjectURL(blob);
|
link.href = window.URL.createObjectURL(blob);
|
||||||
console.log("no msSaveBlob download the report saveblob done");
|
console.log("no msSaveBlob download the report saveblob done");
|
||||||
//link.download? = fileName;
|
//link.download? = fileName;
|
||||||
link.download = fileName;
|
link.download = fileName;
|
||||||
link.click();
|
link.click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** Get the attachment file name */
|
/** Get the attachment file name */
|
||||||
static getFileName(response:any, defaultFileName:string) {
|
static getFileName(response:any, defaultFileName:string) {
|
||||||
const contentDis = response.headers.get('content-disposition');
|
const contentDis = response.headers.get('content-disposition');
|
||||||
let fileName =defaultFileName;
|
let fileName =defaultFileName;
|
||||||
if (contentDis && contentDis.indexOf('attachment') !== -1) {
|
if (contentDis && contentDis.indexOf('attachment') !== -1) {
|
||||||
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
|
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
|
||||||
const matches = filenameRegex.exec(contentDis);
|
const matches = filenameRegex.exec(contentDis);
|
||||||
if (matches != null && matches[1]) {
|
if (matches != null && matches[1]) {
|
||||||
fileName = matches[1].replace(/['"]/g, '');
|
fileName = matches[1].replace(/['"]/g, '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,77 +1,77 @@
|
|||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { firstValueFrom, Observable } from 'rxjs';
|
import { firstValueFrom, Observable } from 'rxjs';
|
||||||
export function initializeApp_old(appInitService: AppSettingService) {
|
export function initializeApp_old(appInitService: AppSettingService) {
|
||||||
return (): Promise<any> => {
|
return (): Promise<any> => {
|
||||||
return appInitService.loadAppSetting_p();
|
return appInitService.loadAppSetting_p();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
export function initializeApp() {
|
export function initializeApp() {
|
||||||
return (): Promise<any> => {
|
return (): Promise<any> => {
|
||||||
return inject(AppSettingService).loadAppSetting_p();
|
return inject(AppSettingService).loadAppSetting_p();
|
||||||
}
|
}
|
||||||
// return () => inject(AppSettingService).loadAppSetting();
|
// return () => inject(AppSettingService).loadAppSetting();
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class AppSettingService {
|
export class AppSettingService {
|
||||||
private _appsetting: any;
|
private _appsetting: any;
|
||||||
constructor(private http: HttpClient
|
constructor(private http: HttpClient
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public loadAppSetting_p(): Promise<any> {
|
public loadAppSetting_p(): Promise<any> {
|
||||||
const source$ = this.http.get("config/appsetting.json")
|
const source$ = this.http.get("config/appsetting.json")
|
||||||
const rs$ = firstValueFrom(source$)
|
const rs$ = firstValueFrom(source$)
|
||||||
.then(x => {
|
.then(x => {
|
||||||
this._appsetting = x;
|
this._appsetting = x;
|
||||||
console.log("[AppSettingService] assign", x);
|
console.log("[AppSettingService] assign", x);
|
||||||
});
|
});
|
||||||
return rs$;
|
return rs$;
|
||||||
}
|
}
|
||||||
public loadAppSetting(): Observable<any> {
|
public loadAppSetting(): Observable<any> {
|
||||||
const source$ = this.http.get("config/appsetting.json")
|
const source$ = this.http.get("config/appsetting.json")
|
||||||
return source$;
|
return source$;
|
||||||
}
|
}
|
||||||
set appSetting(value: any) {
|
set appSetting(value: any) {
|
||||||
this._appsetting = value;
|
this._appsetting = value;
|
||||||
}
|
}
|
||||||
get appSetting(): any {
|
get appSetting(): any {
|
||||||
return this._appsetting;
|
return this._appsetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
/* angular 19 new one in app.config.ts
|
/* angular 19 new one in app.config.ts
|
||||||
provideAppInitializer(initializeApp()),
|
provideAppInitializer(initializeApp()),
|
||||||
|
|
||||||
/* module put this
|
/* module put this
|
||||||
to use it
|
to use it
|
||||||
in app.module.ts
|
in app.module.ts
|
||||||
add
|
add
|
||||||
1)
|
1)
|
||||||
providers: [
|
providers: [
|
||||||
{ provide : APP_INITIALIZER, multi : true, deps : [AppSettingService],
|
{ provide : APP_INITIALIZER, multi : true, deps : [AppSettingService],
|
||||||
useFactory: initializeApp
|
useFactory: initializeApp
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
2)
|
2)
|
||||||
other this one work too.
|
other this one work too.
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide : APP_INITIALIZER,
|
provide : APP_INITIALIZER,
|
||||||
multi : true,
|
multi : true,
|
||||||
deps : [AppSettingService],
|
deps : [AppSettingService],
|
||||||
useFactory : (appConfigService : AppSettingService) => () => appConfigService.loadAppSetting()
|
useFactory : (appConfigService : AppSettingService) => () => appConfigService.loadAppSetting()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
to use it calling something like this
|
to use it calling something like this
|
||||||
export class TestComponent {
|
export class TestComponent {
|
||||||
public test1ServiceUrl: string;
|
public test1ServiceUrl: string;
|
||||||
|
|
||||||
constructor(public configService: AppConfigService) {
|
constructor(public configService: AppConfigService) {
|
||||||
this.test1ServiceUrl = this.configService.appSetting.test1ServiceUrl;
|
this.test1ServiceUrl = this.configService.appSetting.test1ServiceUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@@ -1,97 +1,97 @@
|
|||||||
import { Injectable, inject } from '@angular/core';
|
import { Injectable, inject } from '@angular/core';
|
||||||
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpInterceptorFn, HttpHandlerFn } from '@angular/common/http';
|
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpInterceptorFn, HttpHandlerFn } from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError } from 'rxjs/operators';
|
import { catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
import { AuthenticationService } from '../user-services';
|
import { AuthenticationService } from '../user-services';
|
||||||
//import { ToastrService } from 'ngx-toastr';
|
//import { ToastrService } from 'ngx-toastr';
|
||||||
import { NavigationExtras, Router } from '@angular/router';
|
import { NavigationExtras, Router } from '@angular/router';
|
||||||
/*
|
/*
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ErrorInterceptor implements HttpInterceptor {
|
export class ErrorInterceptor implements HttpInterceptor {
|
||||||
//private authenticationService: AuthenticationService;
|
//private authenticationService: AuthenticationService;
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
// private toastr: ToastrService,
|
// private toastr: ToastrService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
// console.log("I am intercept to catch error status = 401...", request);
|
// console.log("I am intercept to catch error status = 401...", request);
|
||||||
return next.handle(request).pipe(catchError(err => {
|
return next.handle(request).pipe(catchError(err => {
|
||||||
/* no use yet
|
/* no use yet
|
||||||
if (err) {
|
if (err) {
|
||||||
switch(err.status) {
|
switch(err.status) {
|
||||||
case 400:
|
case 400:
|
||||||
if (err.error.errors) {
|
if (err.error.errors) {
|
||||||
const modalStateErrors = [];
|
const modalStateErrors = [];
|
||||||
for (const key in err.error.errors) {
|
for (const key in err.error.errors) {
|
||||||
if (err.error.errors[key]) {
|
if (err.error.errors[key]) {
|
||||||
modalStateErrors.push(err.error.errors[key]);
|
modalStateErrors.push(err.error.errors[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw modalStateErrors;
|
throw modalStateErrors;
|
||||||
} else {
|
} else {
|
||||||
this.toastr.error(err.statusText, err.status);
|
this.toastr.error(err.statusText, err.status);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 401:
|
case 401:
|
||||||
this.toastr.error(err.statusText, err.status);
|
this.toastr.error(err.statusText, err.status);
|
||||||
break;
|
break;
|
||||||
case 404:
|
case 404:
|
||||||
this.router.navigateByUrl('/not-found');
|
this.router.navigateByUrl('/not-found');
|
||||||
break;
|
break;
|
||||||
case 500:
|
case 500:
|
||||||
const navigationExtras: NavigationExtras = {state:{error:err.error}};
|
const navigationExtras: NavigationExtras = {state:{error:err.error}};
|
||||||
this.router.navigateByUrl('/server-error', navigationExtras);
|
this.router.navigateByUrl('/server-error', navigationExtras);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this.toastr.error('Something unexpected went wrong');
|
this.toastr.error('Something unexpected went wrong');
|
||||||
console.log("this error interceptor",err);
|
console.log("this error interceptor",err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
if (err.status === 401) {
|
if (err.status === 401) {
|
||||||
// auto logout if 401 response returned from api Unauthorized
|
// auto logout if 401 response returned from api Unauthorized
|
||||||
// this.authenticationService.logout();
|
// this.authenticationService.logout();
|
||||||
//location.reload();
|
//location.reload();
|
||||||
const error = err.error.message || err.statusText;
|
const error = err.error.message || err.statusText;
|
||||||
console.log("After I Get Error status = 401...", error, err);
|
console.log("After I Get Error status = 401...", error, err);
|
||||||
return throwError(error);
|
return throwError(error);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log("I Get Error .", err);
|
console.log("I Get Error .", err);
|
||||||
return throwError(err);
|
return throwError(err);
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
//new one
|
//new one
|
||||||
//https://blog.ninja-squad.com/2022/11/09/angular-http-in-standalone-applications/
|
//https://blog.ninja-squad.com/2022/11/09/angular-http-in-standalone-applications/
|
||||||
////////////////
|
////////////////
|
||||||
export const ErrorInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> => {
|
export const ErrorInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> => {
|
||||||
const authenticationService = inject(AuthenticationService);
|
const authenticationService = inject(AuthenticationService);
|
||||||
|
|
||||||
// logger.log(`Request is on its way to ${req.url}`);
|
// logger.log(`Request is on its way to ${req.url}`);
|
||||||
return next(req).pipe(catchError(err => {
|
return next(req).pipe(catchError(err => {
|
||||||
if (err.status === 401) {
|
if (err.status === 401) {
|
||||||
// auto logout if 401 response returned from api Unauthorized
|
// auto logout if 401 response returned from api Unauthorized
|
||||||
// this.authenticationService.logout();
|
// this.authenticationService.logout();
|
||||||
//location.reload();
|
//location.reload();
|
||||||
const error = err.error.message || err.statusText;
|
const error = err.error.message || err.statusText;
|
||||||
// console.log("After I Get Error status = 401...", error, err);
|
// console.log("After I Get Error status = 401...", error, err);
|
||||||
return throwError(() => error);
|
return throwError(() => error);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log("I Get Error .", err);
|
console.log("I Get Error .", err);
|
||||||
return throwError(() => err);
|
return throwError(() => err);
|
||||||
}
|
}
|
||||||
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
|
|||||||
@@ -1,115 +1,115 @@
|
|||||||
import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http';
|
import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError } from 'rxjs/operators';
|
import { catchError } from 'rxjs/operators';
|
||||||
import { ConfigureUrl } from '../models';
|
import { ConfigureUrl } from '../models';
|
||||||
import { AppSettingService } from './appsetting';
|
import { AppSettingService } from './appsetting';
|
||||||
|
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class HttpUtility {
|
export class HttpUtility {
|
||||||
private baseApiUrl: string = "";
|
private baseApiUrl: string = "";
|
||||||
constructor(private http: HttpClient,
|
constructor(private http: HttpClient,
|
||||||
private appSetting :AppSettingService,
|
private appSetting :AppSettingService,
|
||||||
private router: Router) {
|
private router: Router) {
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* getFile
|
* getFile
|
||||||
* @param url
|
* @param url
|
||||||
*/
|
*/
|
||||||
public getFileAsText(url: string): Observable<any> {
|
public getFileAsText(url: string): Observable<any> {
|
||||||
return this.http
|
return this.http
|
||||||
.get(this.getApiUrl(url), { responseType: 'blob' as 'text' })
|
.get(this.getApiUrl(url), { responseType: 'blob' as 'text' })
|
||||||
.pipe(catchError(e => this.handleError(e)));
|
.pipe(catchError(e => this.handleError(e)));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* getFile
|
* getFile
|
||||||
* @param url
|
* @param url
|
||||||
*/
|
*/
|
||||||
public getFile(url: string): Observable<any> {
|
public getFile(url: string): Observable<any> {
|
||||||
return this.http
|
return this.http
|
||||||
.get(this.getApiUrl(url), { responseType: 'blob' as 'json' })
|
.get(this.getApiUrl(url), { responseType: 'blob' as 'json' })
|
||||||
.pipe(catchError(e => this.handleError(e)));
|
.pipe(catchError(e => this.handleError(e)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handleError
|
* handleError
|
||||||
* @param response
|
* @param response
|
||||||
*/
|
*/
|
||||||
private handleError(errorResponse: HttpErrorResponse) {
|
private handleError(errorResponse: HttpErrorResponse) {
|
||||||
// in a real world app, we may send the server to some remote logging infrastructure
|
// in a real world app, we may send the server to some remote logging infrastructure
|
||||||
// instead of just logging it to the console
|
// instead of just logging it to the console
|
||||||
return throwError(errorResponse);
|
return throwError(errorResponse);
|
||||||
}
|
}
|
||||||
//get excel file zip file etc ..
|
//get excel file zip file etc ..
|
||||||
/*
|
/*
|
||||||
allowedToDisplay = [
|
allowedToDisplay = [
|
||||||
this.mimeConstant.png,
|
this.mimeConstant.png,
|
||||||
this.mimeConstant.jpeg,
|
this.mimeConstant.jpeg,
|
||||||
this.mimeConstant.jpg,
|
this.mimeConstant.jpg,
|
||||||
this.mimeConstant.gif,
|
this.mimeConstant.gif,
|
||||||
this.mimeConstant.txt,
|
this.mimeConstant.txt,
|
||||||
this.mimeConstant.pdf
|
this.mimeConstant.pdf
|
||||||
];
|
];
|
||||||
*/
|
*/
|
||||||
/* how to use it
|
/* how to use it
|
||||||
this.http.getFileResponse(`Person/GetPhoto?recordId=${personId}`).pipe(
|
this.http.getFileResponse(`Person/GetPhoto?recordId=${personId}`).pipe(
|
||||||
catchError(err => {
|
catchError(err => {
|
||||||
this.snackBar.error(err || this.constants.error_Getting_photo);
|
this.snackBar.error(err || this.constants.error_Getting_photo);
|
||||||
return EMPTY;
|
return EMPTY;
|
||||||
}),
|
}),
|
||||||
finalize(() => {
|
finalize(() => {
|
||||||
this.spinner.hide();
|
this.spinner.hide();
|
||||||
})).subscribe(response => {
|
})).subscribe(response => {
|
||||||
if (response) {
|
if (response) {
|
||||||
if (isDownload) {
|
if (isDownload) {
|
||||||
CommonUtilities.downloadFile(response);
|
CommonUtilities.downloadFile(response);
|
||||||
} else {
|
} else {
|
||||||
if (response.body && response.body.type) {
|
if (response.body && response.body.type) {
|
||||||
if (this.allowedToDisplay.includes(response.body.type)) {
|
if (this.allowedToDisplay.includes(response.body.type)) {
|
||||||
CommonUtilities.displayFileInNewTab(response);
|
CommonUtilities.displayFileInNewTab(response);
|
||||||
} else {
|
} else {
|
||||||
this.temporaryFile = response;
|
this.temporaryFile = response;
|
||||||
this.downloadWarning = true;
|
this.downloadWarning = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
public getFileResponse(url: string, data?: any): Observable<any> {
|
public getFileResponse(url: string, data?: any): Observable<any> {
|
||||||
if (data) {
|
if (data) {
|
||||||
return this.http.post(this.getApiUrl(url),
|
return this.http.post(this.getApiUrl(url),
|
||||||
data,
|
data,
|
||||||
{ responseType: 'blob', observe: 'response' })
|
{ responseType: 'blob', observe: 'response' })
|
||||||
.pipe(catchError(e => this.handleError(e)));
|
.pipe(catchError(e => this.handleError(e)));
|
||||||
|
|
||||||
}
|
}
|
||||||
return this.http
|
return this.http
|
||||||
.get(this.getApiUrl(url), { responseType: 'blob', observe: 'response' })
|
.get(this.getApiUrl(url), { responseType: 'blob', observe: 'response' })
|
||||||
.pipe(catchError(e => this.handleError(e)));
|
.pipe(catchError(e => this.handleError(e)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFileAsPDF(url: string, data: any): Observable<any> {
|
public getFileAsPDF(url: string, data: any): Observable<any> {
|
||||||
let updateURL;
|
let updateURL;
|
||||||
if (data) {
|
if (data) {
|
||||||
updateURL = url + data;
|
updateURL = url + data;
|
||||||
} else {
|
} else {
|
||||||
updateURL = url;
|
updateURL = url;
|
||||||
}
|
}
|
||||||
return this.http
|
return this.http
|
||||||
.get(this.getApiUrl(updateURL), { responseType: 'blob' as 'text', observe: 'response' })
|
.get(this.getApiUrl(updateURL), { responseType: 'blob' as 'text', observe: 'response' })
|
||||||
.pipe(catchError(e => this.handleError(e)));
|
.pipe(catchError(e => this.handleError(e)));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* getApiUrl
|
* getApiUrl
|
||||||
* @param url
|
* @param url
|
||||||
*/
|
*/
|
||||||
private getApiUrl(url:string) {
|
private getApiUrl(url:string) {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl;
|
const baseUrl = this.appSetting.appSetting.baseUrl;
|
||||||
return baseUrl + "/"+ url;
|
return baseUrl + "/"+ url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
export * from './utils';
|
export * from './utils';
|
||||||
export {initializeApp, AppSettingService} from './appsetting';
|
export {initializeApp, AppSettingService} from './appsetting';
|
||||||
export * from './error.interceptor';
|
export * from './error.interceptor';
|
||||||
export * from './jwt.interceptor';
|
export * from './jwt.interceptor';
|
||||||
export * from './lookup.service';
|
export * from './lookup.service';
|
||||||
export * from './httpfile.service';
|
export * from './httpfile.service';
|
||||||
export * from './CommonUtilities';
|
export * from './CommonUtilities';
|
||||||
export * from './timeinput';
|
export * from './timeinput';
|
||||||
+1553
-1553
File diff suppressed because it is too large
Load Diff
@@ -1,47 +1,47 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpInterceptorFn, HttpHandlerFn } from '@angular/common/http';
|
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpInterceptorFn, HttpHandlerFn } from '@angular/common/http';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { Utils } from './utils';
|
import { Utils } from './utils';
|
||||||
/*
|
/*
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class JwtInterceptor implements HttpInterceptor {
|
export class JwtInterceptor implements HttpInterceptor {
|
||||||
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
// add authorization header with jwt token if available
|
// add authorization header with jwt token if available
|
||||||
const currentUser = Utils.getCurrentUser();//localStorage.getItem('currentUser')!;
|
const currentUser = Utils.getCurrentUser();//localStorage.getItem('currentUser')!;
|
||||||
console.log('I am interceptor debug for currentUser obj', currentUser);
|
console.log('I am interceptor debug for currentUser obj', currentUser);
|
||||||
if (currentUser && currentUser.token) {
|
if (currentUser && currentUser.token) {
|
||||||
//console.log('I am interceptor add authorization header with jwt token');
|
//console.log('I am interceptor add authorization header with jwt token');
|
||||||
request = request.clone({
|
request = request.clone({
|
||||||
setHeaders: {
|
setHeaders: {
|
||||||
Authorization: `Bearer ${currentUser.token}`
|
Authorization: `Bearer ${currentUser.token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return next.handle(request);
|
return next.handle(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
new one
|
new one
|
||||||
////////////////
|
////////////////
|
||||||
*/
|
*/
|
||||||
export const JwtInterceptor: HttpInterceptorFn = (request: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> => {
|
export const JwtInterceptor: HttpInterceptorFn = (request: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> => {
|
||||||
//const logger = inject(Logger);
|
//const logger = inject(Logger);
|
||||||
//logger.log(`Request is on its way to ${req.url}`);
|
//logger.log(`Request is on its way to ${req.url}`);
|
||||||
const currentUser = Utils.getCurrentUser();//localStorage.getItem('currentUser')!;
|
const currentUser = Utils.getCurrentUser();//localStorage.getItem('currentUser')!;
|
||||||
// console.log('I am interceptor debug for currentUser obj', currentUser);
|
// console.log('I am interceptor debug for currentUser obj', currentUser);
|
||||||
if (currentUser && currentUser.token && currentUser.token != "") {
|
if (currentUser && currentUser.token && currentUser.token != "") {
|
||||||
// console.log('I am interceptor add authorization header with jwt token');
|
// console.log('I am interceptor add authorization header with jwt token');
|
||||||
request = request.clone({
|
request = request.clone({
|
||||||
setHeaders: {
|
setHeaders: {
|
||||||
Authorization: `Bearer ${currentUser.token}`
|
Authorization: `Bearer ${currentUser.token}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return next(request);
|
return next(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
/*
|
/*
|
||||||
providers: [provideHttpClient(withInterceptors([loggerInterceptor]))]
|
providers: [provideHttpClient(withInterceptors([loggerInterceptor]))]
|
||||||
*/
|
*/
|
||||||
+136
-136
@@ -1,136 +1,136 @@
|
|||||||
import { Injectable, Inject , Output} from '@angular/core';
|
import { Injectable, Inject , Output} from '@angular/core';
|
||||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { ConfigureUrl,Lookup,LookupEdit,ResultModel
|
import { ConfigureUrl,Lookup,LookupEdit,ResultModel
|
||||||
} from '../models';
|
} from '../models';
|
||||||
import { Utils,AppSettingService } from '../shares';
|
import { Utils,AppSettingService } from '../shares';
|
||||||
|
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class LookupService {
|
export class LookupService {
|
||||||
msg: string = "[lookupService] ";
|
msg: string = "[lookupService] ";
|
||||||
_lookupByStatus:any;
|
_lookupByStatus:any;
|
||||||
_staffList:any;
|
_staffList:any;
|
||||||
_clientList:any;
|
_clientList:any;
|
||||||
_jobList:any;
|
_jobList:any;
|
||||||
constructor(private http: HttpClient,
|
constructor(private http: HttpClient,
|
||||||
private appSetting :AppSettingService
|
private appSetting :AppSettingService
|
||||||
) {
|
) {
|
||||||
// this default when load look for previous login information
|
// this default when load look for previous login information
|
||||||
// if no need then comment out downthere
|
// if no need then comment out downthere
|
||||||
this.setAllNull();
|
this.setAllNull();
|
||||||
}
|
}
|
||||||
setAllNull() :void {
|
setAllNull() :void {
|
||||||
// this._lhdList = undefined;
|
// this._lhdList = undefined;
|
||||||
this._lookupByStatus = {};
|
this._lookupByStatus = {};
|
||||||
this._staffList = null;
|
this._staffList = null;
|
||||||
this._clientList = null;
|
this._clientList = null;
|
||||||
this._jobList = null;
|
this._jobList = null;
|
||||||
}
|
}
|
||||||
loadLookupEditBystatus(type:string): Observable<ResultModel<LookupEdit[]>> {
|
loadLookupEditBystatus(type:string): Observable<ResultModel<LookupEdit[]>> {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl + "/LoadLookupEdit";
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl + "/LoadLookupEdit";
|
||||||
const params = new HttpParams().append('type', type);
|
const params = new HttpParams().append('type', type);
|
||||||
console.log(this.msg + "go server this loadLookupEditBystatus is in cache ", type);
|
console.log(this.msg + "go server this loadLookupEditBystatus is in cache ", type);
|
||||||
return this.http.get<ResultModel<LookupEdit[]>>(baseUrl, {params});
|
return this.http.get<ResultModel<LookupEdit[]>>(baseUrl, {params});
|
||||||
}
|
}
|
||||||
loadLookupById(id:number, type:string): Observable<ResultModel<LookupEdit>> {
|
loadLookupById(id:number, type:string): Observable<ResultModel<LookupEdit>> {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl;
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl;
|
||||||
const params = new HttpParams()
|
const params = new HttpParams()
|
||||||
.append('id', id)
|
.append('id', id)
|
||||||
.append('type', type);
|
.append('type', type);
|
||||||
return this.http.get<ResultModel<LookupEdit>>(baseUrl,{params});
|
return this.http.get<ResultModel<LookupEdit>>(baseUrl,{params});
|
||||||
}
|
}
|
||||||
saveLookup(item:LookupEdit): Observable<ResultModel<number>> { //insert Lookup
|
saveLookup(item:LookupEdit): Observable<ResultModel<number>> { //insert Lookup
|
||||||
this.setAllNull();
|
this.setAllNull();
|
||||||
let config = { headers : { 'Content-Type': 'application/json' } };
|
let config = { headers : { 'Content-Type': 'application/json' } };
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl;
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl;
|
||||||
return this.http.post<ResultModel<number>>(baseUrl, item, config);
|
return this.http.post<ResultModel<number>>(baseUrl, item, config);
|
||||||
}
|
}
|
||||||
deleteLookup(id:number): Observable<ResultModel<number>>{
|
deleteLookup(id:number): Observable<ResultModel<number>>{
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl;
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl;
|
||||||
return this.http.delete<ResultModel<number>>(baseUrl + "/" + id );
|
return this.http.delete<ResultModel<number>>(baseUrl + "/" + id );
|
||||||
}
|
}
|
||||||
|
|
||||||
loadLookupBystatus(type:string): Observable<ResultModel<Lookup[]>> {
|
loadLookupBystatus(type:string): Observable<ResultModel<Lookup[]>> {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl + "/LoadJobs";
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl + "/LoadJobs";
|
||||||
console.log(this.msg + "loadLookupBystatus", this._lookupByStatus);
|
console.log(this.msg + "loadLookupBystatus", this._lookupByStatus);
|
||||||
if (this._lookupByStatus[type])
|
if (this._lookupByStatus[type])
|
||||||
{
|
{
|
||||||
console.log(this.msg + "Not go server this LoadJobs is in cache ",type);
|
console.log(this.msg + "Not go server this LoadJobs is in cache ",type);
|
||||||
return of(this._lookupByStatus[type]);
|
return of(this._lookupByStatus[type]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const params = new HttpParams().append('type', type);
|
const params = new HttpParams().append('type', type);
|
||||||
console.log(this.msg + "go server this loadLookupBystatus is in cache ", type);
|
console.log(this.msg + "go server this loadLookupBystatus is in cache ", type);
|
||||||
return this.http.get<ResultModel<Lookup[]>>(baseUrl, {params})
|
return this.http.get<ResultModel<Lookup[]>>(baseUrl, {params})
|
||||||
.pipe(map(resultModel => {
|
.pipe(map(resultModel => {
|
||||||
this._lookupByStatus[type] = resultModel;
|
this._lookupByStatus[type] = resultModel;
|
||||||
return resultModel;
|
return resultModel;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadStaffs(): Observable<ResultModel<Lookup[]>> {
|
loadStaffs(): Observable<ResultModel<Lookup[]>> {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl + "/GetStaffs";
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl + "/GetStaffs";
|
||||||
/* const params = new HttpParams()
|
/* const params = new HttpParams()
|
||||||
.append('id', id)
|
.append('id', id)
|
||||||
.append('type', type);
|
.append('type', type);
|
||||||
return this.http.get<ResultModel<LookupEdit>>(baseUrl,{params});
|
return this.http.get<ResultModel<LookupEdit>>(baseUrl,{params});
|
||||||
*/
|
*/
|
||||||
if (this._staffList != null)
|
if (this._staffList != null)
|
||||||
{
|
{
|
||||||
return of(this._staffList);
|
return of(this._staffList);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return this.http.get<ResultModel<Lookup[]>>(baseUrl)
|
return this.http.get<ResultModel<Lookup[]>>(baseUrl)
|
||||||
.pipe(map( x => {
|
.pipe(map( x => {
|
||||||
this._staffList = x;
|
this._staffList = x;
|
||||||
return x;
|
return x;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadClients(): Observable<ResultModel<Lookup[]>> {
|
loadClients(): Observable<ResultModel<Lookup[]>> {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl + "/GetClients";
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl + "/GetClients";
|
||||||
/* const params = new HttpParams()
|
/* const params = new HttpParams()
|
||||||
.append('id', id)
|
.append('id', id)
|
||||||
.append('type', type);
|
.append('type', type);
|
||||||
return this.http.get<ResultModel<LookupEdit>>(baseUrl,{params});
|
return this.http.get<ResultModel<LookupEdit>>(baseUrl,{params});
|
||||||
*/
|
*/
|
||||||
if (this._clientList != null)
|
if (this._clientList != null)
|
||||||
{
|
{
|
||||||
return of(this._clientList);
|
return of(this._clientList);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return this.http.get<ResultModel<Lookup[]>>(baseUrl)
|
return this.http.get<ResultModel<Lookup[]>>(baseUrl)
|
||||||
.pipe(map(resultModel => {
|
.pipe(map(resultModel => {
|
||||||
this._clientList = resultModel;
|
this._clientList = resultModel;
|
||||||
return resultModel;
|
return resultModel;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadJobs(): Observable<ResultModel<Lookup[]>> {
|
loadJobs(): Observable<ResultModel<Lookup[]>> {
|
||||||
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl + "/GetJobs";
|
const baseUrl = this.appSetting.appSetting.baseUrl + "/"+ ConfigureUrl.lookupUrl + "/GetJobs";
|
||||||
/* const params = new HttpParams()
|
/* const params = new HttpParams()
|
||||||
.append('id', id)
|
.append('id', id)
|
||||||
.append('type', type);
|
.append('type', type);
|
||||||
return this.http.get<ResultModel<LookupEdit>>(baseUrl,{params});
|
return this.http.get<ResultModel<LookupEdit>>(baseUrl,{params});
|
||||||
*/
|
*/
|
||||||
if (this._jobList != null)
|
if (this._jobList != null)
|
||||||
{
|
{
|
||||||
return of(this._jobList);
|
return of(this._jobList);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return this.http.get<ResultModel<Lookup[]>>(baseUrl)
|
return this.http.get<ResultModel<Lookup[]>>(baseUrl)
|
||||||
.pipe(map(x => {
|
.pipe(map(x => {
|
||||||
this._jobList = x;
|
this._jobList = x;
|
||||||
return x;
|
return x;
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+149
-149
@@ -1,149 +1,149 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Component, Input, forwardRef, OnInit, OnDestroy } from '@angular/core';
|
import { Component, Input, forwardRef, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR,ReactiveFormsModule, FormControl, Validators } from '@angular/forms';
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR,ReactiveFormsModule, FormControl, Validators } from '@angular/forms';
|
||||||
import { Subject, takeUntil } from 'rxjs';
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'time-input',
|
selector: 'time-input',
|
||||||
imports:[ReactiveFormsModule,CommonModule],
|
imports:[ReactiveFormsModule,CommonModule],
|
||||||
template: `
|
template: `
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
[formControl]="timeControl"
|
[formControl]="timeControl"
|
||||||
(input)="onInput($event)"
|
(input)="onInput($event)"
|
||||||
(blur)="onBlur()"
|
(blur)="onBlur()"
|
||||||
class="time-input"
|
class="time-input"
|
||||||
style="width: 80px; text-align: center;"
|
style="width: 80px; text-align: center;"
|
||||||
/>
|
/>
|
||||||
`,
|
`,
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
useExisting: forwardRef(() => TimeInputComponent),
|
useExisting: forwardRef(() => TimeInputComponent),
|
||||||
multi: true,
|
multi: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class TimeInputComponent implements ControlValueAccessor, OnInit, OnDestroy {
|
export class TimeInputComponent implements ControlValueAccessor, OnInit, OnDestroy {
|
||||||
@Input() placeholder: string = 'HH:MM';
|
@Input() placeholder: string = 'HH:MM';
|
||||||
@Input() initialValue: string = ''; // Added initialValue input
|
@Input() initialValue: string = ''; // Added initialValue input
|
||||||
@Input() disabled: boolean = false;
|
@Input() disabled: boolean = false;
|
||||||
|
|
||||||
timeControl = new FormControl('', [
|
timeControl = new FormControl('', [
|
||||||
Validators.pattern(/^([0-2][0-9]:[0-5][0-9])?$/), // Added more precise regex
|
Validators.pattern(/^([0-2][0-9]:[0-5][0-9])?$/), // Added more precise regex
|
||||||
]);
|
]);
|
||||||
|
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
private _value: string = '';
|
private _value: string = '';
|
||||||
private onChange: (value: string) => void = () => {};
|
private onChange: (value: string) => void = () => {};
|
||||||
private onTouched: () => void = () => {};
|
private onTouched: () => void = () => {};
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.timeControl.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => {
|
this.timeControl.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((value) => {
|
||||||
this.onChange(value || ''); // Pass the value to the parent form
|
this.onChange(value || ''); // Pass the value to the parent form
|
||||||
});
|
});
|
||||||
if (this.initialValue) {
|
if (this.initialValue) {
|
||||||
this.writeValue(this.initialValue);
|
this.writeValue(this.initialValue);
|
||||||
}
|
}
|
||||||
this.timeControl.disable();
|
this.timeControl.disable();
|
||||||
if(!this.disabled){
|
if(!this.disabled){
|
||||||
this.timeControl.enable();
|
this.timeControl.enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.destroy$.next();
|
this.destroy$.next();
|
||||||
this.destroy$.complete();
|
this.destroy$.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
get value(): string {
|
get value(): string {
|
||||||
return this._value;
|
return this._value;
|
||||||
}
|
}
|
||||||
|
|
||||||
set value(val: string) {
|
set value(val: string) {
|
||||||
this._value = val;
|
this._value = val;
|
||||||
this.onChange(val);
|
this.onChange(val);
|
||||||
this.onTouched();
|
this.onTouched();
|
||||||
}
|
}
|
||||||
|
|
||||||
writeValue(value: string): void {
|
writeValue(value: string): void {
|
||||||
this._value = value || '';
|
this._value = value || '';
|
||||||
this.formatInput(this._value); // Use the formatting function
|
this.formatInput(this._value); // Use the formatting function
|
||||||
}
|
}
|
||||||
|
|
||||||
registerOnChange(fn: (value: string) => void): void {
|
registerOnChange(fn: (value: string) => void): void {
|
||||||
this.onChange = fn;
|
this.onChange = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerOnTouched(fn: () => void): void {
|
registerOnTouched(fn: () => void): void {
|
||||||
this.onTouched = fn;
|
this.onTouched = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
setDisabledState(isDisabled: boolean): void {
|
setDisabledState(isDisabled: boolean): void {
|
||||||
this.disabled = isDisabled;
|
this.disabled = isDisabled;
|
||||||
if (isDisabled) {
|
if (isDisabled) {
|
||||||
this.timeControl.disable();
|
this.timeControl.disable();
|
||||||
} else {
|
} else {
|
||||||
this.timeControl.enable();
|
this.timeControl.enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onInput(event: Event): void {
|
onInput(event: Event): void {
|
||||||
let input = (event.target as HTMLInputElement).value;
|
let input = (event.target as HTMLInputElement).value;
|
||||||
input = input.replace(/[^0-9]/g, ''); // Remove non-numeric characters.
|
input = input.replace(/[^0-9]/g, ''); // Remove non-numeric characters.
|
||||||
|
|
||||||
if (input.length > 4) {
|
if (input.length > 4) {
|
||||||
input = input.slice(0, 4); // Limit to 4 digits
|
input = input.slice(0, 4); // Limit to 4 digits
|
||||||
}
|
}
|
||||||
|
|
||||||
let formatted = '';
|
let formatted = '';
|
||||||
if (input.length > 2) {
|
if (input.length > 2) {
|
||||||
formatted = input.slice(0, 2) + ':' + input.slice(2);
|
formatted = input.slice(0, 2) + ':' + input.slice(2);
|
||||||
} else {
|
} else {
|
||||||
formatted = input;
|
formatted = input;
|
||||||
}
|
}
|
||||||
this.timeControl.setValue(formatted, { emitEvent: false }); // Prevent infinite loop
|
this.timeControl.setValue(formatted, { emitEvent: false }); // Prevent infinite loop
|
||||||
this.value = formatted;
|
this.value = formatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
onBlur(): void {
|
onBlur(): void {
|
||||||
this.onTouched();
|
this.onTouched();
|
||||||
if (this.timeControl.valid) {
|
if (this.timeControl.valid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.timeControl.value?.length === 0) {
|
if (this.timeControl.value?.length === 0) {
|
||||||
this.timeControl.setValue('', {emitEvent: false});
|
this.timeControl.setValue('', {emitEvent: false});
|
||||||
this.value = '';
|
this.value = '';
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.formatInput(this.timeControl.value);
|
this.formatInput(this.timeControl.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private formatInput(val: string | null): void {
|
private formatInput(val: string | null): void {
|
||||||
if (!val) {
|
if (!val) {
|
||||||
this.timeControl.setValue('', {emitEvent: false});
|
this.timeControl.setValue('', {emitEvent: false});
|
||||||
this.value = '';
|
this.value = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let numbersOnly = val.replace(/[^0-9]/g, '');
|
let numbersOnly = val.replace(/[^0-9]/g, '');
|
||||||
let formatted = '';
|
let formatted = '';
|
||||||
|
|
||||||
if (numbersOnly.length > 2) {
|
if (numbersOnly.length > 2) {
|
||||||
formatted = numbersOnly.slice(0, 2) + ':' + numbersOnly.slice(2, 4);
|
formatted = numbersOnly.slice(0, 2) + ':' + numbersOnly.slice(2, 4);
|
||||||
} else {
|
} else {
|
||||||
formatted = numbersOnly;
|
formatted = numbersOnly;
|
||||||
}
|
}
|
||||||
if (formatted.length === 5 && this.timeControl.valid) {
|
if (formatted.length === 5 && this.timeControl.valid) {
|
||||||
this.timeControl.setValue(formatted, {emitEvent: false});
|
this.timeControl.setValue(formatted, {emitEvent: false});
|
||||||
this.value = formatted;
|
this.value = formatted;
|
||||||
} else if (numbersOnly.length <= 2) {
|
} else if (numbersOnly.length <= 2) {
|
||||||
this.timeControl.setValue(formatted, {emitEvent: false});
|
this.timeControl.setValue(formatted, {emitEvent: false});
|
||||||
this.value = formatted;
|
this.value = formatted;
|
||||||
} else {
|
} else {
|
||||||
this.timeControl.setValue('00:00', {emitEvent: false});
|
this.timeControl.setValue('00:00', {emitEvent: false});
|
||||||
this.value = '00:00'
|
this.value = '00:00'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+218
-218
@@ -1,219 +1,219 @@
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { Person, User, userRole } from "../models"
|
import { Person, User, userRole } from "../models"
|
||||||
import { TreeNode } from "primeng/api";
|
import { TreeNode } from "@openng/optimus-ui/api";
|
||||||
|
|
||||||
type MyProName = "fatherId" | "motherId";
|
type MyProName = "fatherId" | "motherId";
|
||||||
|
|
||||||
export class Utils {
|
export class Utils {
|
||||||
static toBase64 (file:any)
|
static toBase64 (file:any)
|
||||||
{
|
{
|
||||||
let promise = new Promise((resolve, reject) => {
|
let promise = new Promise((resolve, reject) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
reader.onload = () => resolve(reader.result);
|
reader.onload = () => resolve(reader.result);
|
||||||
reader.onerror = reject;
|
reader.onerror = reject;
|
||||||
});
|
});
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
static getBase64(file: any) {
|
static getBase64(file: any) {
|
||||||
let result: any;
|
let result: any;
|
||||||
var reader = new FileReader();
|
var reader = new FileReader();
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
reader.onload = function () {
|
reader.onload = function () {
|
||||||
result = reader.result;
|
result = reader.result;
|
||||||
console.log('tobase64 ', result);
|
console.log('tobase64 ', result);
|
||||||
};
|
};
|
||||||
reader.onerror = function (error) {
|
reader.onerror = function (error) {
|
||||||
console.log('Error: ', error);
|
console.log('Error: ', error);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
static getCurrentUser(): User {
|
static getCurrentUser(): User {
|
||||||
|
|
||||||
let myUser = new User();
|
let myUser = new User();
|
||||||
myUser.username = "";
|
myUser.username = "";
|
||||||
const obj = sessionStorage.getItem('currentUser');
|
const obj = sessionStorage.getItem('currentUser');
|
||||||
//const obj = localStorage.getItem('currentUser');
|
//const obj = localStorage.getItem('currentUser');
|
||||||
if (obj != undefined) {
|
if (obj != undefined) {
|
||||||
let user = JSON.parse(obj);
|
let user = JSON.parse(obj);
|
||||||
myUser.firstName = user.firstName;
|
myUser.firstName = user.firstName;
|
||||||
myUser.id = user.id;
|
myUser.id = user.id;
|
||||||
myUser.lastName = user.lastName;
|
myUser.lastName = user.lastName;
|
||||||
myUser.role = user.role;
|
myUser.role = user.role;
|
||||||
myUser.username = user.username;
|
myUser.username = user.username;
|
||||||
myUser.email = user.email;
|
myUser.email = user.email;
|
||||||
myUser.token = user.token;
|
myUser.token = user.token;
|
||||||
myUser.phone = user.phone;
|
myUser.phone = user.phone;
|
||||||
myUser.department = user.department;
|
myUser.department = user.department;
|
||||||
myUser.position = user.position;
|
myUser.position = user.position;
|
||||||
myUser.managerEmail = user.managerEmail;
|
myUser.managerEmail = user.managerEmail;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// console.log("[util] getcurrentUser",myUser);
|
// console.log("[util] getcurrentUser",myUser);
|
||||||
return myUser;
|
return myUser;
|
||||||
}
|
}
|
||||||
static setLocalStore(user: User): void {
|
static setLocalStore(user: User): void {
|
||||||
if (user && user.token) {
|
if (user && user.token) {
|
||||||
// store user details and jwt token in local storage to keep user logged in between page refreshes
|
// store user details and jwt token in local storage to keep user logged in between page refreshes
|
||||||
// localStorage.setItem('currentUser', JSON.stringify(user));
|
// localStorage.setItem('currentUser', JSON.stringify(user));
|
||||||
sessionStorage.setItem('currentUser', JSON.stringify(user));
|
sessionStorage.setItem('currentUser', JSON.stringify(user));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getLastMonth(): Date {
|
static getLastMonth(): Date {
|
||||||
let result = moment().subtract(1, 'months').toDate();
|
let result = moment().subtract(1, 'months').toDate();
|
||||||
result.setDate(1);
|
result.setDate(1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
static getHome(): string {
|
static getHome(): string {
|
||||||
let result ="";
|
let result ="";
|
||||||
const user = this.getCurrentUser();
|
const user = this.getCurrentUser();
|
||||||
const urole = user.role;
|
const urole = user.role;
|
||||||
if (urole == userRole.Accounting)
|
if (urole == userRole.Accounting)
|
||||||
{
|
{
|
||||||
result = "staffworkw";
|
result = "staffworkw";
|
||||||
}
|
}
|
||||||
else if (urole == userRole.Admin)
|
else if (urole == userRole.Admin)
|
||||||
{
|
{
|
||||||
result = "staff";
|
result = "staff";
|
||||||
}
|
}
|
||||||
else if (urole == userRole.ServiceManager)
|
else if (urole == userRole.ServiceManager)
|
||||||
{
|
{
|
||||||
result = "servicetask";
|
result = "servicetask";
|
||||||
}
|
}
|
||||||
else if (urole == userRole.WorkShop)
|
else if (urole == userRole.WorkShop)
|
||||||
{
|
{
|
||||||
result = "staffwork";
|
result = "staffwork";
|
||||||
}
|
}
|
||||||
else if (urole == userRole.Normal)
|
else if (urole == userRole.Normal)
|
||||||
{
|
{
|
||||||
result = "staff";
|
result = "staff";
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
static getTimeStr(val:Date): string {
|
static getTimeStr(val:Date): string {
|
||||||
let result = "00:00";
|
let result = "00:00";
|
||||||
if (val)
|
if (val)
|
||||||
{
|
{
|
||||||
const hh = val.getHours();
|
const hh = val.getHours();
|
||||||
const min = val.getMinutes();
|
const min = val.getMinutes();
|
||||||
if (hh < 10)
|
if (hh < 10)
|
||||||
result = '0' + hh.toString();
|
result = '0' + hh.toString();
|
||||||
else
|
else
|
||||||
result = hh.toString();
|
result = hh.toString();
|
||||||
if (min < 10)
|
if (min < 10)
|
||||||
result = result + ":0" + min.toString();
|
result = result + ":0" + min.toString();
|
||||||
else
|
else
|
||||||
result = result + ":" + min.toString();
|
result = result + ":" + min.toString();
|
||||||
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
static canRunReport(role: number): boolean {
|
static canRunReport(role: number): boolean {
|
||||||
let result = false;
|
let result = false;
|
||||||
if (role == userRole.Admin)
|
if (role == userRole.Admin)
|
||||||
result = true;
|
result = true;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
static getUserRole(user: User): number {
|
static getUserRole(user: User): number {
|
||||||
/*
|
/*
|
||||||
sysadmin
|
sysadmin
|
||||||
request_manager
|
request_manager
|
||||||
ward_user
|
ward_user
|
||||||
*/
|
*/
|
||||||
let ret = 0;
|
let ret = 0;
|
||||||
if (user) {
|
if (user) {
|
||||||
// console.log("utils user", user);
|
// console.log("utils user", user);
|
||||||
if (user.role)
|
if (user.role)
|
||||||
ret = user.role;
|
ret = user.role;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
static getIsAuth(): boolean {
|
static getIsAuth(): boolean {
|
||||||
const user = this.getCurrentUser();
|
const user = this.getCurrentUser();
|
||||||
if (user.username != "") {
|
if (user.username != "") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
static getAdminRoleName(): number {
|
static getAdminRoleName(): number {
|
||||||
return userRole.Admin;
|
return userRole.Admin;
|
||||||
}
|
}
|
||||||
static clearCurrentUser(): void {
|
static clearCurrentUser(): void {
|
||||||
sessionStorage.clear();
|
sessionStorage.clear();
|
||||||
//localStorage.clear();
|
//localStorage.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
static formatNode(item:Person): TreeNode
|
static formatNode(item:Person): TreeNode
|
||||||
{
|
{
|
||||||
let label = item.lastName + " " + item.firstName;
|
let label = item.lastName + " " + item.firstName;
|
||||||
let key = item.id.toString();
|
let key = item.id.toString();
|
||||||
let node: TreeNode ={
|
let node: TreeNode ={
|
||||||
key,
|
key,
|
||||||
label,
|
label,
|
||||||
type: 'person',
|
type: 'person',
|
||||||
data: {title: item.title, name: label, image: item.image},
|
data: {title: item.title, name: label, image: item.image},
|
||||||
icon: 'pi pi-user'
|
icon: 'pi pi-user'
|
||||||
};
|
};
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
static getFileExtension(filename: string): string {
|
static getFileExtension(filename: string): string {
|
||||||
const lastDotIndex = filename.lastIndexOf('.');
|
const lastDotIndex = filename.lastIndexOf('.');
|
||||||
if (lastDotIndex !== -1 && lastDotIndex < filename.length - 1) { // Ensure a dot exists and is not the last character
|
if (lastDotIndex !== -1 && lastDotIndex < filename.length - 1) { // Ensure a dot exists and is not the last character
|
||||||
return filename.substring(lastDotIndex + 1);
|
return filename.substring(lastDotIndex + 1);
|
||||||
}
|
}
|
||||||
return ''; // No extension found
|
return ''; // No extension found
|
||||||
}
|
}
|
||||||
static getChildForParentId(proName: MyProName , pid: number,childressNodes: Person[]): TreeNode[] {
|
static getChildForParentId(proName: MyProName , pid: number,childressNodes: Person[]): TreeNode[] {
|
||||||
let result: TreeNode[] =[];
|
let result: TreeNode[] =[];
|
||||||
let tree_node_child: TreeNode[];
|
let tree_node_child: TreeNode[];
|
||||||
let node:TreeNode;
|
let node:TreeNode;
|
||||||
let item: Person;
|
let item: Person;
|
||||||
|
|
||||||
const children = childressNodes.filter(x => x[proName] == pid);
|
const children = childressNodes.filter(x => x[proName] == pid);
|
||||||
for (let c = 0; c < children.length; c++)
|
for (let c = 0; c < children.length; c++)
|
||||||
{
|
{
|
||||||
item = children[c];
|
item = children[c];
|
||||||
node = this.formatNode(item);
|
node = this.formatNode(item);
|
||||||
tree_node_child = this.getChildForParentId(proName,item.id, childressNodes);
|
tree_node_child = this.getChildForParentId(proName,item.id, childressNodes);
|
||||||
console.log("getChildForParentId childressNodes item tree_node_child ", childressNodes, item, tree_node_child);
|
console.log("getChildForParentId childressNodes item tree_node_child ", childressNodes, item, tree_node_child);
|
||||||
if (tree_node_child.length > 0)
|
if (tree_node_child.length > 0)
|
||||||
{
|
{
|
||||||
node.expanded = true;
|
node.expanded = true;
|
||||||
node.children = tree_node_child;
|
node.children = tree_node_child;
|
||||||
}
|
}
|
||||||
result.push(node);
|
result.push(node);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static populateNode(proName: MyProName, familyList: Person[]): TreeNode[] {
|
static populateNode(proName: MyProName, familyList: Person[]): TreeNode[] {
|
||||||
let familyTree: TreeNode[] = [];
|
let familyTree: TreeNode[] = [];
|
||||||
let node:TreeNode;
|
let node:TreeNode;
|
||||||
let child_nodes:TreeNode[];
|
let child_nodes:TreeNode[];
|
||||||
|
|
||||||
let childressNodes:Person[];
|
let childressNodes:Person[];
|
||||||
|
|
||||||
let item: Person;
|
let item: Person;
|
||||||
const topNodes = familyList.filter(x => x[proName]! < 1);
|
const topNodes = familyList.filter(x => x[proName]! < 1);
|
||||||
childressNodes = familyList.filter(x => x[proName]! > 0);
|
childressNodes = familyList.filter(x => x[proName]! > 0);
|
||||||
for(let i = 0; i < topNodes.length; i++)
|
for(let i = 0; i < topNodes.length; i++)
|
||||||
{
|
{
|
||||||
item = topNodes[i];
|
item = topNodes[i];
|
||||||
node = Utils.formatNode(item);
|
node = Utils.formatNode(item);
|
||||||
child_nodes = this.getChildForParentId(proName, item.id,childressNodes);
|
child_nodes = this.getChildForParentId(proName, item.id,childressNodes);
|
||||||
console.log("populate getchildrenForParentId", child_nodes);
|
console.log("populate getchildrenForParentId", child_nodes);
|
||||||
if (child_nodes.length > 0)
|
if (child_nodes.length > 0)
|
||||||
{
|
{
|
||||||
node.expanded = true;
|
node.expanded = true;
|
||||||
node.children = child_nodes;
|
node.children = child_nodes;
|
||||||
}
|
}
|
||||||
familyTree.push(node);
|
familyTree.push(node);
|
||||||
//childressNodes =
|
//childressNodes =
|
||||||
}
|
}
|
||||||
return familyTree;
|
return familyTree;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export * from './staff.component';
|
export * from './staff.component';
|
||||||
export * from './staff.edit.component';
|
export * from './staff.edit.component';
|
||||||
export * from './staff.service';
|
export * from './staff.service';
|
||||||
export * from './staff.pass.component';
|
export * from './staff.pass.component';
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-form-field {
|
.mat-form-field {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
td.mat-column-edit, .mat-column-delete {
|
td.mat-column-edit, .mat-column-delete {
|
||||||
width: 35px;
|
width: 35px;
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +1,64 @@
|
|||||||
<div class="shadow-2xl rounded p-2 mt-2">
|
<div class="shadow-2xl rounded p-2 mt-2">
|
||||||
<h3>Staff List</h3>
|
<h3>Staff List</h3>
|
||||||
<div>
|
<div>
|
||||||
<form>
|
<form>
|
||||||
<div class="grid md:grid-cols-4 gap-2">
|
<div class="grid md:grid-cols-4 gap-2">
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="login">Email</label>
|
<label for="login">Email</label>
|
||||||
<input id="login" pInputText name="login" type="text" [(ngModel)]="email"
|
<input id="login" pInputText name="login" type="text" [(ngModel)]="email"
|
||||||
class="inputfield w-full p-inputtext-sm">
|
class="inputfield w-full p-inputtext-sm">
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="lastname1">Surname</label>
|
<label for="lastname1">Surname</label>
|
||||||
<input id="lastname1" pInputText name="lastname" type="text" [(ngModel)]="lastname"
|
<input id="lastname1" pInputText name="lastname" type="text" [(ngModel)]="lastname"
|
||||||
class="inputfield w-full p-inputtext-sm">
|
class="inputfield w-full p-inputtext-sm">
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="firstname">First Name</label>
|
<label for="firstname">First Name</label>
|
||||||
<input id="firstname" name="firstname" pInputText type="text" [(ngModel)]="firstname"
|
<input id="firstname" name="firstname" pInputText type="text" [(ngModel)]="firstname"
|
||||||
class="inputfield w-full p-inputtext-sm">
|
class="inputfield w-full p-inputtext-sm">
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-end">
|
<div class="flex items-end">
|
||||||
<button pButton pRipple class="p-button-sm mr-2 " type="submit" icon="pi pi-search" iconPos="left" label="Search"
|
<button pButton pRipple class="p-button-sm mr-2 " type="submit" icon="pi pi-search" iconPos="left" label="Search"
|
||||||
(click)="search()"></button>
|
(click)="search()"></button>
|
||||||
<button pButton pRipple class="p-button-sm " type="button" icon="pi pi-user-plus" iconPos="left" label="New Staff"
|
<button pButton pRipple class="p-button-sm " type="button" icon="pi pi-user-plus" iconPos="left" label="New Staff"
|
||||||
(click)="newUser()"></button>
|
(click)="newUser()"></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<!--[value]="userList"-->
|
<!--[value]="userList"-->
|
||||||
<p-table [value]="users()" sortMode="multiple"
|
<p-table [value]="users()" sortMode="multiple"
|
||||||
class="p-datatable-sm" [loading]="loading">
|
class="p-datatable-sm" [loading]="loading">
|
||||||
<ng-template pTemplate="header">
|
<ng-template pTemplate="header">
|
||||||
<tr>
|
<tr>
|
||||||
<th pSortableColumn="email">Email<p-sortIcon field="email"></p-sortIcon>
|
<th pSortableColumn="email">Email<p-sortIcon field="email"></p-sortIcon>
|
||||||
</th>
|
</th>
|
||||||
<th pSortableColumn="lastname">Surname <p-sortIcon field="lastname"></p-sortIcon>
|
<th pSortableColumn="lastname">Surname <p-sortIcon field="lastname"></p-sortIcon>
|
||||||
</th>
|
</th>
|
||||||
<th pSortableColumn="firstname">First Name <p-sortIcon field="firstname"></p-sortIcon>
|
<th pSortableColumn="firstname">First Name <p-sortIcon field="firstname"></p-sortIcon>
|
||||||
</th>
|
</th>
|
||||||
|
|
||||||
<th >Active </th>
|
<th >Active </th>
|
||||||
<th>Edit</th>
|
<th>Edit</th>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template pTemplate="body" let-user>
|
<ng-template pTemplate="body" let-user>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{user.email}}</td>
|
<td>{{user.email}}</td>
|
||||||
<td>{{user.lastname}}</td>
|
<td>{{user.lastname}}</td>
|
||||||
<td>{{user.firstname}}</td>
|
<td>{{user.firstname}}</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
<i class="pi" [ngClass]="{'true-icon pi-check-circle': user.active, 'false-icon pi-times-circle': !user.active}"></i>
|
<i class="pi" [ngClass]="{'true-icon pi-check-circle': user.active, 'false-icon pi-times-circle': !user.active}"></i>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button pButton type="button" icon="pi pi-pencil" class="p-button-rounded p-button-text"
|
<button pButton type="button" icon="pi pi-pencil" class="p-button-rounded p-button-text"
|
||||||
(click)="edit(user.id)"></button>
|
(click)="edit(user.id)"></button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-table>
|
</p-table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+162
-162
@@ -1,162 +1,162 @@
|
|||||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, inject, ChangeDetectorRef} from '@angular/core';
|
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, inject, ChangeDetectorRef} from '@angular/core';
|
||||||
|
|
||||||
import { StaffView ,StaffSearch } from '../models';
|
import { StaffView ,StaffSearch } from '../models';
|
||||||
|
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { StaffsActions, StaffsApiActions } from '../state/staff.actions';
|
import { StaffsActions, StaffsApiActions } from '../state/staff.actions';
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { StaffService } from './staff.service';
|
import { StaffService } from './staff.service';
|
||||||
import { AuthenticationService } from '../user-services';
|
import { AuthenticationService } from '../user-services';
|
||||||
import { TableModule } from 'primeng/table';
|
import { TableModule } from '@openng/optimus-ui/table';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { ButtonModule } from 'primeng/button';
|
import { ButtonModule } from '@openng/optimus-ui/button';
|
||||||
import { InputTextModule } from 'primeng/inputtext';
|
import { InputTextModule } from '@openng/optimus-ui/inputtext';
|
||||||
import { selectStaffLoaded,selectStaff } from '../state/staff.selectors';
|
import { selectStaffLoaded,selectStaff } from '../state/staff.selectors';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'staff-list',
|
selector: 'staff-list',
|
||||||
templateUrl: './staff.component.html',
|
templateUrl: './staff.component.html',
|
||||||
imports:[TableModule,FormsModule,CommonModule,ButtonModule,InputTextModule],
|
imports:[TableModule,FormsModule,CommonModule,ButtonModule,InputTextModule],
|
||||||
styleUrls: ['./staff.component.css'],
|
styleUrls: ['./staff.component.css'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class StaffComponent implements OnInit, OnDestroy{
|
export class StaffComponent implements OnInit, OnDestroy{
|
||||||
private readonly store = inject(Store);
|
private readonly store = inject(Store);
|
||||||
private subscription:Subscription = new Subscription();
|
private subscription:Subscription = new Subscription();
|
||||||
firstname = '';
|
firstname = '';
|
||||||
email = '';
|
email = '';
|
||||||
lastname = '';
|
lastname = '';
|
||||||
loading = false;
|
loading = false;
|
||||||
userList:StaffView[] = [];
|
userList:StaffView[] = [];
|
||||||
users = this.store.selectSignal(selectStaff);
|
users = this.store.selectSignal(selectStaff);
|
||||||
staffloadyet = this.store.selectSignal(selectStaffLoaded)
|
staffloadyet = this.store.selectSignal(selectStaffLoaded)
|
||||||
private cd = inject(ChangeDetectorRef);
|
private cd = inject(ChangeDetectorRef);
|
||||||
msg ="[Staff component]";
|
msg ="[Staff component]";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
private store: Store<appValidationState>
|
private store: Store<appValidationState>
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
private staffService: StaffService,
|
private staffService: StaffService,
|
||||||
private authenticationService: AuthenticationService,
|
private authenticationService: AuthenticationService,
|
||||||
private router: Router
|
private router: Router
|
||||||
) {}
|
) {}
|
||||||
getSearchCiteria(): StaffSearch {
|
getSearchCiteria(): StaffSearch {
|
||||||
let criteria:StaffSearch = {
|
let criteria:StaffSearch = {
|
||||||
email: this.email,
|
email: this.email,
|
||||||
firstName: this.firstname,
|
firstName: this.firstname,
|
||||||
lastName: this.lastname,
|
lastName: this.lastname,
|
||||||
};
|
};
|
||||||
|
|
||||||
return criteria;
|
return criteria;
|
||||||
|
|
||||||
}
|
}
|
||||||
canSearch():boolean {
|
canSearch():boolean {
|
||||||
let result = false;
|
let result = false;
|
||||||
result = this.email !== "";
|
result = this.email !== "";
|
||||||
result = result || this.lastname !== "";
|
result = result || this.lastname !== "";
|
||||||
result = result || this.firstname !== "";
|
result = result || this.firstname !== "";
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
ngOnInit(): void
|
ngOnInit(): void
|
||||||
{
|
{
|
||||||
this.authenticationService.isHome = false;
|
this.authenticationService.isHome = false;
|
||||||
this.authenticationService.isReport = false;
|
this.authenticationService.isReport = false;
|
||||||
const prev = this.staffService.searchCriteria;
|
const prev = this.staffService.searchCriteria;
|
||||||
let goload = true;
|
let goload = true;
|
||||||
if (prev.lastName !== '')
|
if (prev.lastName !== '')
|
||||||
{
|
{
|
||||||
this.lastname = prev.lastName;
|
this.lastname = prev.lastName;
|
||||||
goload = true;
|
goload = true;
|
||||||
}
|
}
|
||||||
if (prev.firstName !== '')
|
if (prev.firstName !== '')
|
||||||
{
|
{
|
||||||
this.firstname = prev.firstName;
|
this.firstname = prev.firstName;
|
||||||
goload = true;
|
goload = true;
|
||||||
}
|
}
|
||||||
if (prev.email !== '')
|
if (prev.email !== '')
|
||||||
{
|
{
|
||||||
this.email = prev.email;
|
this.email = prev.email;
|
||||||
goload = true;
|
goload = true;
|
||||||
}
|
}
|
||||||
if (goload)
|
if (goload)
|
||||||
{
|
{
|
||||||
this.search();
|
this.search();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getActive(active:boolean):string {
|
getActive(active:boolean):string {
|
||||||
let result = 'false-icon pi-times-circle';
|
let result = 'false-icon pi-times-circle';
|
||||||
if (active)
|
if (active)
|
||||||
result = 'true-icon pi-check-circle';
|
result = 'true-icon pi-check-circle';
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
search():void {
|
search():void {
|
||||||
const canSearch = true; // this.canSearch();
|
const canSearch = true; // this.canSearch();
|
||||||
if (canSearch)
|
if (canSearch)
|
||||||
{
|
{
|
||||||
|
|
||||||
const criteria = this.getSearchCiteria();
|
const criteria = this.getSearchCiteria();
|
||||||
this.staffService.searchCriteria = criteria;
|
this.staffService.searchCriteria = criteria;
|
||||||
console.log("search function store staffload yet",this.staffloadyet(), this.users);
|
console.log("search function store staffload yet",this.staffloadyet(), this.users);
|
||||||
if (this.staffloadyet() != true) {
|
if (this.staffloadyet() != true) {
|
||||||
this.store.dispatch(StaffsActions.loadStaff({criteria}));
|
this.store.dispatch(StaffsActions.loadStaff({criteria}));
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if (this.staffloadyet() != true) {
|
if (this.staffloadyet() != true) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const loadStaff$ = this.staffService.searchStaffs(criteria);
|
const loadStaff$ = this.staffService.searchStaffs(criteria);
|
||||||
this.subscription.add(
|
this.subscription.add(
|
||||||
loadStaff$.subscribe( {
|
loadStaff$.subscribe( {
|
||||||
next: result => {
|
next: result => {
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
|
||||||
this.userList = result.data;
|
this.userList = result.data;
|
||||||
this.store.dispatch(StaffsApiActions.loadStaffSuccess({staffs:this.userList, staffLoad: true}));
|
this.store.dispatch(StaffsApiActions.loadStaffSuccess({staffs:this.userList, staffLoad: true}));
|
||||||
this.cd.detectChanges();
|
this.cd.detectChanges();
|
||||||
},
|
},
|
||||||
error: e => {
|
error: e => {
|
||||||
const message = e || e.message;
|
const message = e || e.message;
|
||||||
// this.toastr.error(message);
|
// this.toastr.error(message);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
console.log("error ", e);
|
console.log("error ", e);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newUser():void {
|
newUser():void {
|
||||||
//console.log("add new employee");
|
//console.log("add new employee");
|
||||||
this.router.navigate( ['/staff/new'], { queryParams: {returnUrl:'/staff' } });
|
this.router.navigate( ['/staff/new'], { queryParams: {returnUrl:'/staff' } });
|
||||||
}
|
}
|
||||||
edit(id: number) : void {
|
edit(id: number) : void {
|
||||||
//console.log("edit staff", id);
|
//console.log("edit staff", id);
|
||||||
this.router.navigate( ['/staff/'+id], { queryParams: {returnUrl:'/staff' } });
|
this.router.navigate( ['/staff/'+id], { queryParams: {returnUrl:'/staff' } });
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteItem(id: number): void {
|
deleteItem(id: number): void {
|
||||||
this.staffService.deleteStaff(id)
|
this.staffService.deleteStaff(id)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe({ next: result => {
|
.subscribe({ next: result => {
|
||||||
console.log(this.msg + " deleteItem success", result);
|
console.log(this.msg + " deleteItem success", result);
|
||||||
//let data = this.dataSource.data;
|
//let data = this.dataSource.data;
|
||||||
//let index: number = data.findIndex(d => d.id === id);
|
//let index: number = data.findIndex(d => d.id === id);
|
||||||
// console.log(this.msg + "delete from datasource");
|
// console.log(this.msg + "delete from datasource");
|
||||||
//data.splice(index, 1)
|
//data.splice(index, 1)
|
||||||
//this.dataSource.data = data;
|
//this.dataSource.data = data;
|
||||||
},
|
},
|
||||||
error: e => console.error(e)
|
error: e => console.error(e)
|
||||||
});
|
});
|
||||||
//console.log(this.msg + "click button to delete");
|
//console.log(this.msg + "click button to delete");
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.subscription.unsubscribe();
|
this.subscription.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user