Frontend first draft
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
class AuthorizationFailed implements Exception {
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
class ErrorFailedToReadImage implements Exception {
|
||||
}
|
||||
2
frontend/pshared/lib/api/errors/unauthorized.dart
Normal file
2
frontend/pshared/lib/api/errors/unauthorized.dart
Normal file
@@ -0,0 +1,2 @@
|
||||
class ErrorUnauthorized implements Exception {
|
||||
}
|
||||
2
frontend/pshared/lib/api/errors/upload_failed.dart
Normal file
2
frontend/pshared/lib/api/errors/upload_failed.dart
Normal file
@@ -0,0 +1,2 @@
|
||||
class ErrorUploadFailed implements Exception {
|
||||
}
|
||||
18
frontend/pshared/lib/api/requests/change_password.dart
Normal file
18
frontend/pshared/lib/api/requests/change_password.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'change_password.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class ChangePassword {
|
||||
@JsonKey(name: 'old')
|
||||
final String oldPassword;
|
||||
|
||||
@JsonKey(name: 'new')
|
||||
final String newPassword;
|
||||
|
||||
const ChangePassword({required this.oldPassword, required this.newPassword});
|
||||
|
||||
factory ChangePassword.fromJson(Map<String, dynamic> json) => _$ChangePasswordFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$ChangePasswordToJson(this);
|
||||
}
|
||||
18
frontend/pshared/lib/api/requests/change_role.dart
Normal file
18
frontend/pshared/lib/api/requests/change_role.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'change_role.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class ChangeRole {
|
||||
final String accountRef;
|
||||
final String newRoleDescriptionRef;
|
||||
|
||||
const ChangeRole({
|
||||
required this.accountRef,
|
||||
required this.newRoleDescriptionRef,
|
||||
});
|
||||
|
||||
factory ChangeRole.fromJson(Map<String, dynamic> json) => _$ChangeRoleFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$ChangeRoleToJson(this);
|
||||
}
|
||||
15
frontend/pshared/lib/api/requests/file_upload.dart
Normal file
15
frontend/pshared/lib/api/requests/file_upload.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'file_upload.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class FileUpload {
|
||||
|
||||
final String objRef;
|
||||
|
||||
const FileUpload({ required this.objRef });
|
||||
|
||||
factory FileUpload.fromJson(Map<String, dynamic> json) => _$FileUploadFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$FileUploadToJson(this);
|
||||
}
|
||||
24
frontend/pshared/lib/api/requests/login.dart
Normal file
24
frontend/pshared/lib/api/requests/login.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'login.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class LoginRequest {
|
||||
final String login;
|
||||
final String password;
|
||||
final String locale;
|
||||
final String clientId;
|
||||
final String deviceId;
|
||||
|
||||
const LoginRequest({
|
||||
required this.login,
|
||||
required this.password,
|
||||
required this.locale,
|
||||
required this.clientId,
|
||||
required this.deviceId,
|
||||
});
|
||||
|
||||
factory LoginRequest.fromJson(Map<String, dynamic> json) => _$LoginRequestFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$LoginRequestToJson(this);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/permissions/data/policy.dart';
|
||||
import 'package:pshared/data/mapper/permissions/data/policy.dart';
|
||||
import 'package:pshared/models/permissions/data/policy.dart';
|
||||
|
||||
part 'change_policies.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class PoliciesChangeRequest {
|
||||
final List<PolicyDTO>? add;
|
||||
final List<PolicyDTO>? remove;
|
||||
|
||||
const PoliciesChangeRequest({
|
||||
this.add,
|
||||
this.remove,
|
||||
});
|
||||
|
||||
factory PoliciesChangeRequest.add({required List<Policy> policies}) => PoliciesChangeRequest(
|
||||
add: policies.map((policy) => policy.toDTO()).toList(),
|
||||
);
|
||||
|
||||
factory PoliciesChangeRequest.remove({required List<Policy> policies}) => PoliciesChangeRequest(
|
||||
remove: policies.map((policy) => policy.toDTO()).toList(),
|
||||
);
|
||||
|
||||
factory PoliciesChangeRequest.change({
|
||||
required List<Policy> add,
|
||||
required List<Policy> remove,
|
||||
}) => PoliciesChangeRequest(
|
||||
add: add.map((policy) => policy.toDTO()).toList(),
|
||||
remove: remove.map((policy) => policy.toDTO()).toList(),
|
||||
);
|
||||
|
||||
factory PoliciesChangeRequest.fromJson(Map<String, dynamic> json) => _$PoliciesChangeRequestFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$PoliciesChangeRequestToJson(this);
|
||||
}
|
||||
42
frontend/pshared/lib/api/requests/signup.dart
Normal file
42
frontend/pshared/lib/api/requests/signup.dart
Normal file
@@ -0,0 +1,42 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'signup.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class SignupRequest {
|
||||
final String name;
|
||||
final String login;
|
||||
final String password;
|
||||
final String locale;
|
||||
final String organizationName;
|
||||
final String organizationTimeZone;
|
||||
|
||||
const SignupRequest({
|
||||
required this.name,
|
||||
required this.login,
|
||||
required this.password,
|
||||
required this.locale,
|
||||
required this.organizationName,
|
||||
required this.organizationTimeZone,
|
||||
});
|
||||
|
||||
factory SignupRequest.build({
|
||||
required String name,
|
||||
required String login,
|
||||
required String password,
|
||||
required String locale,
|
||||
required String organizationName,
|
||||
required String organizationTimeZone,
|
||||
}) => SignupRequest(
|
||||
name: name,
|
||||
login: login,
|
||||
password: password,
|
||||
locale: locale,
|
||||
organizationName: organizationName,
|
||||
organizationTimeZone: organizationTimeZone,
|
||||
);
|
||||
|
||||
factory SignupRequest.fromJson(Map<String, dynamic> json) => _$SignupRequestFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$SignupRequestToJson(this);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import 'package:pshared/api/requests/tokens/refresh_rotate.dart';
|
||||
|
||||
|
||||
typedef AccessTokenRefreshRequest = RotateRefreshTokenRequest;
|
||||
21
frontend/pshared/lib/api/requests/tokens/refresh_rotate.dart
Normal file
21
frontend/pshared/lib/api/requests/tokens/refresh_rotate.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/api/requests/tokens/session_id.dart';
|
||||
|
||||
part 'refresh_rotate.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class RotateRefreshTokenRequest extends SessionID {
|
||||
final String token;
|
||||
|
||||
const RotateRefreshTokenRequest({
|
||||
required this.token,
|
||||
required super.clientId,
|
||||
required super.deviceId,
|
||||
});
|
||||
|
||||
factory RotateRefreshTokenRequest.fromJson(Map<String, dynamic> json) => _$RotateRefreshTokenRequestFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$RotateRefreshTokenRequestToJson(this);
|
||||
}
|
||||
18
frontend/pshared/lib/api/requests/tokens/session_id.dart
Normal file
18
frontend/pshared/lib/api/requests/tokens/session_id.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'session_id.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class SessionID {
|
||||
final String clientId;
|
||||
final String deviceId;
|
||||
|
||||
const SessionID({
|
||||
required this.clientId,
|
||||
required this.deviceId,
|
||||
});
|
||||
|
||||
factory SessionID.fromJson(Map<String, dynamic> json) => _$SessionIDFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$SessionIDToJson(this);
|
||||
}
|
||||
18
frontend/pshared/lib/api/responses/account.dart
Normal file
18
frontend/pshared/lib/api/responses/account.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/api/responses/token.dart';
|
||||
import 'package:pshared/data/dto/account/account.dart';
|
||||
|
||||
part 'account.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class AccountResponse {
|
||||
final AccountDTO account;
|
||||
final TokenData accessToken;
|
||||
|
||||
const AccountResponse({required this.accessToken, required this.account});
|
||||
|
||||
factory AccountResponse.fromJson(Map<String, dynamic> json) => _$AccountResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$AccountResponseToJson(this);
|
||||
}
|
||||
16
frontend/pshared/lib/api/responses/base.dart
Normal file
16
frontend/pshared/lib/api/responses/base.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/api/responses/token.dart';
|
||||
|
||||
part 'base.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class BaseAuthorizedResponse {
|
||||
final TokenData accessToken;
|
||||
|
||||
const BaseAuthorizedResponse({required this.accessToken});
|
||||
|
||||
factory BaseAuthorizedResponse.fromJson(Map<String, dynamic> json) => _$BaseAuthorizedResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$BaseAuthorizedResponseToJson(this);
|
||||
}
|
||||
18
frontend/pshared/lib/api/responses/employees.dart
Normal file
18
frontend/pshared/lib/api/responses/employees.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/api/responses/token.dart';
|
||||
import 'package:pshared/data/dto/account/account.dart';
|
||||
|
||||
part 'employees.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class EmployeesResponse {
|
||||
final List<AccountDTO> accounts;
|
||||
final TokenData accessToken;
|
||||
|
||||
const EmployeesResponse({required this.accessToken, required this.accounts});
|
||||
|
||||
factory EmployeesResponse.fromJson(Map<String, dynamic> json) => _$EmployeesResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$EmployeesResponseToJson(this);
|
||||
}
|
||||
13
frontend/pshared/lib/api/responses/error/connectivity.dart
Normal file
13
frontend/pshared/lib/api/responses/error/connectivity.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
class ConnectivityError implements Exception {
|
||||
final int? code;
|
||||
final String message;
|
||||
|
||||
const ConnectivityError({this.code, required this.message});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return code == null
|
||||
? 'Error response, message: $message)'
|
||||
: 'Error response (code: $code, message: $message)';
|
||||
}
|
||||
}
|
||||
43
frontend/pshared/lib/api/responses/error/server.dart
Normal file
43
frontend/pshared/lib/api/responses/error/server.dart
Normal file
@@ -0,0 +1,43 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'server.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class ErrorResponse implements Exception {
|
||||
final int code;
|
||||
final String details;
|
||||
final String source;
|
||||
final String error;
|
||||
|
||||
const ErrorResponse({
|
||||
required this.code,
|
||||
required this.details,
|
||||
required this.error,
|
||||
required this.source,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final buffer = StringBuffer('Error response (code: $code');
|
||||
|
||||
if (details.isNotEmpty) {
|
||||
buffer.write(', details: $details');
|
||||
}
|
||||
|
||||
if (error.isNotEmpty) {
|
||||
buffer.write(', error: $error');
|
||||
}
|
||||
|
||||
if (source.isNotEmpty) {
|
||||
buffer.write(', source: $source');
|
||||
}
|
||||
|
||||
buffer.write(')');
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
factory ErrorResponse.fromJson(Map<String, dynamic> json) => _$ErrorResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$ErrorResponseToJson(this);
|
||||
}
|
||||
15
frontend/pshared/lib/api/responses/file_uploaded.dart
Normal file
15
frontend/pshared/lib/api/responses/file_uploaded.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'file_uploaded.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class FileUploaded {
|
||||
|
||||
final String url;
|
||||
|
||||
const FileUploaded({ required this.url });
|
||||
|
||||
factory FileUploaded.fromJson(Map<String, dynamic> json) => _$FileUploadedFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$FileUploadedToJson(this);
|
||||
}
|
||||
19
frontend/pshared/lib/api/responses/login.dart
Normal file
19
frontend/pshared/lib/api/responses/login.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/api/responses/account.dart';
|
||||
import 'package:pshared/api/responses/token.dart';
|
||||
import 'package:pshared/data/dto/account/account.dart';
|
||||
|
||||
part 'login.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class LoginResponse extends AccountResponse {
|
||||
final TokenData refreshToken;
|
||||
|
||||
const LoginResponse({required super.accessToken, required super.account, required this.refreshToken});
|
||||
|
||||
factory LoginResponse.fromJson(Map<String, dynamic> json) => _$LoginResponseFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$LoginResponseToJson(this);
|
||||
}
|
||||
19
frontend/pshared/lib/api/responses/message.dart
Normal file
19
frontend/pshared/lib/api/responses/message.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/api/responses/type.dart';
|
||||
|
||||
part 'message.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class HTTPMessage {
|
||||
|
||||
@JsonKey(fromJson: MessageTypeExtension.fromJson, toJson: MessageTypeExtension.toJson)
|
||||
final MessageType status;
|
||||
final Map<String, dynamic> data;
|
||||
|
||||
const HTTPMessage({ required this.data, required this.status });
|
||||
|
||||
factory HTTPMessage.fromJson(Map<String, dynamic> json) => _$HTTPMessageFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$HTTPMessageToJson(this);
|
||||
}
|
||||
19
frontend/pshared/lib/api/responses/organization.dart
Normal file
19
frontend/pshared/lib/api/responses/organization.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/api/responses/base.dart';
|
||||
import 'package:pshared/api/responses/token.dart';
|
||||
import 'package:pshared/data/dto/organization.dart';
|
||||
|
||||
part 'organization.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class OrganizationResponse extends BaseAuthorizedResponse {
|
||||
final List<OrganizationDTO> organizations;
|
||||
|
||||
const OrganizationResponse({required super.accessToken, required this.organizations});
|
||||
|
||||
factory OrganizationResponse.fromJson(Map<String, dynamic> json) => _$OrganizationResponseFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$OrganizationResponseToJson(this);
|
||||
}
|
||||
21
frontend/pshared/lib/api/responses/policies.dart
Normal file
21
frontend/pshared/lib/api/responses/policies.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/api/responses/base.dart';
|
||||
import 'package:pshared/api/responses/token.dart';
|
||||
import 'package:pshared/data/dto/permissions/data/permissions.dart';
|
||||
import 'package:pshared/data/dto/permissions/description/description.dart';
|
||||
|
||||
part 'policies.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class PoliciesResponse extends BaseAuthorizedResponse {
|
||||
final PermissionsDescriptionDTO descriptions;
|
||||
final PermissionsDataDTO permissions;
|
||||
|
||||
const PoliciesResponse({required this.descriptions, required this.permissions, required super.accessToken});
|
||||
|
||||
factory PoliciesResponse.fromJson(Map<String, dynamic> json) => _$PoliciesResponseFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$PoliciesResponseToJson(this);
|
||||
}
|
||||
15
frontend/pshared/lib/api/responses/token.dart
Normal file
15
frontend/pshared/lib/api/responses/token.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'token.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class TokenData {
|
||||
final String token;
|
||||
final DateTime expiration;
|
||||
|
||||
const TokenData({required this.token, required this.expiration});
|
||||
|
||||
factory TokenData.fromJson(Map<String, dynamic> json) => _$TokenDataFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$TokenDataToJson(this);
|
||||
}
|
||||
32
frontend/pshared/lib/api/responses/type.dart
Normal file
32
frontend/pshared/lib/api/responses/type.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
enum MessageType {
|
||||
success,
|
||||
error,
|
||||
request
|
||||
}
|
||||
|
||||
extension MessageTypeExtension on MessageType {
|
||||
static String toJson(MessageType value) {
|
||||
switch (value) {
|
||||
case MessageType.success:
|
||||
return 'success';
|
||||
case MessageType.error:
|
||||
return 'error';
|
||||
case MessageType.request:
|
||||
return 'request';
|
||||
}
|
||||
}
|
||||
|
||||
static MessageType fromJson(String json) {
|
||||
switch (json) {
|
||||
case 'success':
|
||||
return MessageType.success;
|
||||
case 'error':
|
||||
return MessageType.error;
|
||||
case 'request':
|
||||
return MessageType.request;
|
||||
default:
|
||||
throw ArgumentError('Unknown HTTPMType string: $json');
|
||||
}
|
||||
}
|
||||
}
|
||||
47
frontend/pshared/lib/config/common.dart
Normal file
47
frontend/pshared/lib/config/common.dart
Normal file
@@ -0,0 +1,47 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
class CommonConstants {
|
||||
static String apiProto = const String.fromEnvironment('API_PROTO', defaultValue: 'http');
|
||||
static String apiHost = const String.fromEnvironment('API_HOST', defaultValue: 'localhost');
|
||||
// static String apiHost = 'localhost';
|
||||
// static String apiHost = '10.0.2.2';
|
||||
static String apiEndpoint = '/api/v1';
|
||||
static String amplitudeSecret = 'c3d75b3e2520d708440acbb16b923e79';
|
||||
static String amplitudeServerZone = 'EU';
|
||||
static Locale defaultLocale = const Locale('en');
|
||||
static String defaultCurrency = 'EUR';
|
||||
static int defaultDimensionLength = 500;
|
||||
static String clientId = '';
|
||||
static String wsProto = 'ws';
|
||||
static String wsEndpoint = '/ws';
|
||||
static Color themeColor = Color.fromARGB(255, 80, 63, 224);
|
||||
static String nilObjectRef = '000000000000000000000000';
|
||||
|
||||
// Public getters for shared properties
|
||||
static String get serviceUrl => '$apiProto://$apiHost';
|
||||
static String get apiUrl => '$serviceUrl$apiEndpoint';
|
||||
static String get wsUrl => '$wsProto://$apiHost$apiEndpoint$wsEndpoint';
|
||||
static const String accessTokenStorageKey = 'access_token';
|
||||
static const String refreshTokenStorageKey = 'refresh_token';
|
||||
static const String currentOrgKey = 'current_org';
|
||||
static const String deviceIdStorageKey = 'device_id';
|
||||
|
||||
// Method to apply the configuration, called by platform-specific implementations
|
||||
static void applyConfiguration(Map<String, dynamic> configJson) {
|
||||
apiProto = configJson['apiProto'] ?? apiProto;
|
||||
apiHost = configJson['apiHost'] ?? apiHost;
|
||||
apiEndpoint = configJson['apiEndpoint'] ?? apiEndpoint;
|
||||
amplitudeSecret = configJson['amplitudeSecret'] ?? amplitudeSecret;
|
||||
amplitudeServerZone = configJson['amplitudeServerZone'] ?? amplitudeServerZone;
|
||||
defaultLocale = Locale(configJson['defaultLocale'] ?? defaultLocale.languageCode);
|
||||
defaultCurrency = configJson['defaultCurrency'] ?? defaultCurrency;
|
||||
wsProto = configJson['wsProto'] ?? wsProto;
|
||||
wsEndpoint = configJson['wsEndpoint'] ?? wsEndpoint;
|
||||
defaultDimensionLength = configJson['defaultDimensionLength'] ?? defaultDimensionLength;
|
||||
clientId = configJson['clientId'] ?? clientId;
|
||||
if (configJson.containsKey('themeColor')) {
|
||||
themeColor = Color(int.parse(configJson['themeColor']));
|
||||
}
|
||||
}
|
||||
}
|
||||
2
frontend/pshared/lib/config/constants.dart
Normal file
2
frontend/pshared/lib/config/constants.dart
Normal file
@@ -0,0 +1,2 @@
|
||||
export 'mobile.dart'
|
||||
if (dart.library.html) 'web.dart';
|
||||
35
frontend/pshared/lib/config/mobile.dart
Normal file
35
frontend/pshared/lib/config/mobile.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:pshared/config/common.dart';
|
||||
|
||||
|
||||
class Constants extends CommonConstants {
|
||||
static const String _clientIdMobile = 'com.profee.pay.mobile-3f9c3b76-2f89-4e9e-95a2-1a5b705b7a1d';
|
||||
|
||||
static Locale get defaultLocale => CommonConstants.defaultLocale;
|
||||
static String get clientId => _clientIdMobile;
|
||||
static String get accessTokenStorageKey => CommonConstants.accessTokenStorageKey;
|
||||
static String get refreshTokenStorageKey => CommonConstants.refreshTokenStorageKey;
|
||||
static String get currentOrgKey => CommonConstants.currentOrgKey;
|
||||
static String get apiUrl => CommonConstants.apiUrl;
|
||||
static String get serviceUrl => CommonConstants.serviceUrl;
|
||||
static int get defaultDimensionLength => CommonConstants.defaultDimensionLength;
|
||||
static String get deviceIdStorageKey => CommonConstants.deviceIdStorageKey;
|
||||
static String get nilObjectRef => CommonConstants.nilObjectRef;
|
||||
static Color get themeColor => CommonConstants.themeColor;
|
||||
|
||||
static Future<void> initialize() async {
|
||||
var configFile = File('./config/config.json');
|
||||
if (await configFile.exists()) {
|
||||
var configJson = jsonDecode(await configFile.readAsString());
|
||||
CommonConstants.applyConfiguration({
|
||||
...configJson,
|
||||
'clientId': configJson['clientId'] ?? _clientIdMobile,
|
||||
});
|
||||
} else {
|
||||
CommonConstants.clientId = _clientIdMobile;
|
||||
}
|
||||
}
|
||||
}
|
||||
75
frontend/pshared/lib/config/web.dart
Normal file
75
frontend/pshared/lib/config/web.dart
Normal file
@@ -0,0 +1,75 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'dart:js_interop';
|
||||
|
||||
import 'package:pshared/config/common.dart';
|
||||
|
||||
|
||||
/// Bind to the global JS `appConfig` (if it exists).
|
||||
@JS()
|
||||
external AppConfig? get appConfig;
|
||||
|
||||
/// A staticInterop class for the JS object returned by `appConfig`.
|
||||
@JS()
|
||||
@staticInterop
|
||||
class AppConfig {}
|
||||
|
||||
/// Extension methods to expose each property on `AppConfig`.
|
||||
extension AppConfigExtension on AppConfig {
|
||||
external String? get apiProto;
|
||||
external String? get apiHost;
|
||||
external String? get apiEndpoint;
|
||||
external String? get amplitudeSecret;
|
||||
external String? get amplitudeServerZone;
|
||||
external String? get defaultLocale;
|
||||
external String? get wsProto;
|
||||
external String? get wsEndpoint;
|
||||
external int? get defaultDimensionLength;
|
||||
external String? get themeColor;
|
||||
external String? get clientId;
|
||||
}
|
||||
|
||||
class Constants extends CommonConstants {
|
||||
static const String _clientIdWeb = 'com.profee.pay.web-4b6e8a0f-9b5c-4f57-b3a6-3c456e9bb2cd';
|
||||
|
||||
// Just re-expose these from CommonConstants:
|
||||
static Locale get defaultLocale => CommonConstants.defaultLocale;
|
||||
static String get clientId => _clientIdWeb;
|
||||
static String get accessTokenStorageKey => CommonConstants.accessTokenStorageKey;
|
||||
static String get refreshTokenStorageKey => CommonConstants.refreshTokenStorageKey;
|
||||
static String get currentOrgKey => CommonConstants.currentOrgKey;
|
||||
static String get apiUrl => CommonConstants.apiUrl;
|
||||
static String get serviceUrl => CommonConstants.serviceUrl;
|
||||
static int get defaultDimensionLength => CommonConstants.defaultDimensionLength;
|
||||
static String get deviceIdStorageKey => CommonConstants.deviceIdStorageKey;
|
||||
static String get nilObjectRef => CommonConstants.nilObjectRef;
|
||||
static Color get themeColor => CommonConstants.themeColor;
|
||||
|
||||
static Future<void> initialize() async {
|
||||
// Try to grab the JS `appConfig` if it exists:
|
||||
final config = appConfig;
|
||||
|
||||
if (config != null) {
|
||||
// Build a Dart Map from the JS object’s properties:
|
||||
final configJson = <String, dynamic>{
|
||||
'apiProto': config.apiProto,
|
||||
'apiHost': config.apiHost,
|
||||
'apiEndpoint': config.apiEndpoint,
|
||||
'amplitudeSecret': config.amplitudeSecret,
|
||||
'amplitudeServerZone': config.amplitudeServerZone,
|
||||
'defaultLocale': config.defaultLocale,
|
||||
'wsProto': config.wsProto,
|
||||
'wsEndpoint': config.wsEndpoint,
|
||||
'defaultDimensionLength': config.defaultDimensionLength,
|
||||
'themeColor': config.themeColor,
|
||||
// If the JS side didn’t supply a clientId, fall back to our Dart constant
|
||||
'clientId': config.clientId ?? _clientIdWeb,
|
||||
};
|
||||
|
||||
CommonConstants.applyConfiguration(configJson);
|
||||
} else {
|
||||
// No appConfig on JS side → just use the default Dart client ID.
|
||||
CommonConstants.clientId = _clientIdWeb;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
frontend/pshared/lib/data/dto/account/account.dart
Normal file
25
frontend/pshared/lib/data/dto/account/account.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/account/base.dart';
|
||||
|
||||
part 'account.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class AccountDTO extends AccountBaseDTO {
|
||||
final String login;
|
||||
|
||||
const AccountDTO({
|
||||
required super.id,
|
||||
required super.createdAt,
|
||||
required super.updatedAt,
|
||||
required super.name,
|
||||
required super.avatarUrl,
|
||||
required super.locale,
|
||||
required this.login,
|
||||
});
|
||||
|
||||
factory AccountDTO.fromJson(Map<String, dynamic> json) => _$AccountDTOFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$AccountDTOToJson(this);
|
||||
}
|
||||
27
frontend/pshared/lib/data/dto/account/base.dart
Normal file
27
frontend/pshared/lib/data/dto/account/base.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/storable.dart';
|
||||
|
||||
part 'base.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class AccountBaseDTO extends StorableDTO {
|
||||
final String name;
|
||||
final String locale;
|
||||
final String? avatarUrl;
|
||||
|
||||
const AccountBaseDTO({
|
||||
required super.id,
|
||||
required super.createdAt,
|
||||
required super.updatedAt,
|
||||
required this.name,
|
||||
required this.avatarUrl,
|
||||
required this.locale,
|
||||
});
|
||||
|
||||
factory AccountBaseDTO.fromJson(Map<String, dynamic> json) => _$AccountBaseDTOFromJson(json);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$AccountBaseDTOToJson(this);
|
||||
}
|
||||
23
frontend/pshared/lib/data/dto/organization.dart
Normal file
23
frontend/pshared/lib/data/dto/organization.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:pshared/data/dto/storable.dart';
|
||||
|
||||
part 'organization.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class OrganizationDTO extends StorableDTO {
|
||||
final String timeZone;
|
||||
final String? logoUrl;
|
||||
|
||||
const OrganizationDTO({
|
||||
required super.id,
|
||||
required super.createdAt,
|
||||
required super.updatedAt,
|
||||
required this.timeZone,
|
||||
this.logoUrl,
|
||||
});
|
||||
|
||||
factory OrganizationDTO.fromJson(Map<String, dynamic> json) => _$OrganizationDTOFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$OrganizationDTOToJson(this);
|
||||
}
|
||||
16
frontend/pshared/lib/data/dto/organization/description.dart
Normal file
16
frontend/pshared/lib/data/dto/organization/description.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'description.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class OrganizationDescriptionDTO {
|
||||
final String? logoUrl;
|
||||
|
||||
const OrganizationDescriptionDTO({
|
||||
this.logoUrl,
|
||||
});
|
||||
|
||||
factory OrganizationDescriptionDTO.fromJson(Map<String, dynamic> json) => _$OrganizationDescriptionDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$OrganizationDescriptionDTOToJson(this);
|
||||
}
|
||||
22
frontend/pshared/lib/data/dto/permissions/access.dart
Normal file
22
frontend/pshared/lib/data/dto/permissions/access.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/permissions/data/permissions.dart';
|
||||
import 'package:pshared/data/dto/permissions/description/description.dart';
|
||||
|
||||
part 'access.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class UserAccessDTO {
|
||||
final PermissionsDescriptionDTO descriptions;
|
||||
final PermissionsDataDTO permissions;
|
||||
|
||||
const UserAccessDTO({
|
||||
required this.descriptions,
|
||||
required this.permissions,
|
||||
});
|
||||
|
||||
factory UserAccessDTO.fromJson(Map<String, dynamic> json) => _$UserAccessDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$UserAccessDTOToJson(this);
|
||||
}
|
||||
|
||||
19
frontend/pshared/lib/data/dto/permissions/action_effect.dart
Normal file
19
frontend/pshared/lib/data/dto/permissions/action_effect.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
// data/action_effect_dto.dart
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'action_effect.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class ActionEffectDTO {
|
||||
final String action;
|
||||
final String effect;
|
||||
|
||||
const ActionEffectDTO({
|
||||
required this.action,
|
||||
required this.effect,
|
||||
});
|
||||
|
||||
factory ActionEffectDTO.fromJson(Map<String, dynamic> json) => _$ActionEffectDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$ActionEffectDTOToJson(this);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/permissions/action_effect.dart';
|
||||
|
||||
part 'permission.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class PermissionDTO {
|
||||
final String roleDescriptionRef;
|
||||
final String organizationRef;
|
||||
final String descriptionRef;
|
||||
final String? objectRef;
|
||||
final ActionEffectDTO effect;
|
||||
final String accountRef;
|
||||
|
||||
const PermissionDTO({
|
||||
required this.roleDescriptionRef,
|
||||
required this.organizationRef,
|
||||
required this.descriptionRef,
|
||||
required this.objectRef,
|
||||
required this.effect,
|
||||
required this.accountRef,
|
||||
});
|
||||
|
||||
factory PermissionDTO.fromJson(Map<String, dynamic> json) => _$PermissionDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$PermissionDTOToJson(this);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/permissions/data/permission.dart';
|
||||
import 'package:pshared/data/dto/permissions/data/policy.dart';
|
||||
import 'package:pshared/data/dto/permissions/data/role.dart';
|
||||
|
||||
part 'permissions.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class PermissionsDataDTO {
|
||||
final List<RoleDTO> roles;
|
||||
final List<PolicyDTO> policies;
|
||||
final List<PermissionDTO> permissions;
|
||||
|
||||
const PermissionsDataDTO({
|
||||
required this.roles,
|
||||
required this.policies,
|
||||
required this.permissions,
|
||||
});
|
||||
|
||||
factory PermissionsDataDTO.fromJson(Map<String, dynamic> json) => _$PermissionsDataDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$PermissionsDataDTOToJson(this);
|
||||
}
|
||||
26
frontend/pshared/lib/data/dto/permissions/data/policy.dart
Normal file
26
frontend/pshared/lib/data/dto/permissions/data/policy.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/permissions/action_effect.dart';
|
||||
|
||||
part 'policy.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class PolicyDTO {
|
||||
final String roleDescriptionRef;
|
||||
final String organizationRef;
|
||||
final String descriptionRef;
|
||||
final String? objectRef;
|
||||
final ActionEffectDTO effect;
|
||||
|
||||
const PolicyDTO({
|
||||
required this.roleDescriptionRef,
|
||||
required this.organizationRef,
|
||||
required this.descriptionRef,
|
||||
required this.objectRef,
|
||||
required this.effect,
|
||||
});
|
||||
|
||||
factory PolicyDTO.fromJson(Map<String, dynamic> json) => _$PolicyDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$PolicyDTOToJson(this);
|
||||
}
|
||||
20
frontend/pshared/lib/data/dto/permissions/data/role.dart
Normal file
20
frontend/pshared/lib/data/dto/permissions/data/role.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'role.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class RoleDTO {
|
||||
final String accountRef;
|
||||
final String organizationRef;
|
||||
final String descriptionRef;
|
||||
|
||||
const RoleDTO({
|
||||
required this.accountRef,
|
||||
required this.descriptionRef,
|
||||
required this.organizationRef,
|
||||
});
|
||||
|
||||
factory RoleDTO.fromJson(Map<String, dynamic> json) => _$RoleDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$RoleDTOToJson(this);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/permissions/description/policy.dart';
|
||||
import 'package:pshared/data/dto/permissions/description/role.dart';
|
||||
|
||||
part 'description.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class PermissionsDescriptionDTO {
|
||||
final List<RoleDescriptionDTO> roles;
|
||||
final List<PolicyDescriptionDTO> policies;
|
||||
|
||||
const PermissionsDescriptionDTO({
|
||||
required this.roles,
|
||||
required this.policies,
|
||||
});
|
||||
|
||||
factory PermissionsDescriptionDTO.fromJson(Map<String, dynamic> json) => _$PermissionsDescriptionDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$PermissionsDescriptionDTOToJson(this);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:pshared/data/dto/storable.dart';
|
||||
import 'package:pshared/models/resources.dart';
|
||||
|
||||
part 'policy.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class PolicyDescriptionDTO extends StorableDTO {
|
||||
final List<ResourceType>? resourceTypes;
|
||||
final String? organizationRef;
|
||||
|
||||
const PolicyDescriptionDTO({
|
||||
required super.id,
|
||||
required super.createdAt,
|
||||
required super.updatedAt,
|
||||
required this.resourceTypes,
|
||||
required this.organizationRef,
|
||||
});
|
||||
|
||||
factory PolicyDescriptionDTO.fromJson(Map<String, dynamic> json) => _$PolicyDescriptionDTOFromJson(json);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$PolicyDescriptionDTOToJson(this);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:pshared/data/dto/storable.dart';
|
||||
|
||||
part 'role.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class RoleDescriptionDTO extends StorableDTO {
|
||||
final String organizationRef;
|
||||
|
||||
const RoleDescriptionDTO({
|
||||
required super.id,
|
||||
required super.createdAt,
|
||||
required super.updatedAt,
|
||||
required this.organizationRef,
|
||||
});
|
||||
|
||||
factory RoleDescriptionDTO.fromJson(Map<String, dynamic> json) => _$RoleDescriptionDTOFromJson(json);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$RoleDescriptionDTOToJson(this);
|
||||
}
|
||||
0
frontend/pshared/lib/data/dto/pfe/services.dart
Normal file
0
frontend/pshared/lib/data/dto/pfe/services.dart
Normal file
20
frontend/pshared/lib/data/dto/storable.dart
Normal file
20
frontend/pshared/lib/data/dto/storable.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'storable.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class StorableDTO {
|
||||
final String id;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
|
||||
const StorableDTO({
|
||||
required this.id,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
});
|
||||
|
||||
factory StorableDTO.fromJson(Map<String, dynamic> json) => _$StorableDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$StorableDTOToJson(this);
|
||||
}
|
||||
BIN
frontend/pshared/lib/data/mapper/.DS_Store
vendored
Normal file
BIN
frontend/pshared/lib/data/mapper/.DS_Store
vendored
Normal file
Binary file not shown.
26
frontend/pshared/lib/data/mapper/account/account.dart
Normal file
26
frontend/pshared/lib/data/mapper/account/account.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'package:pshared/data/dto/account/account.dart';
|
||||
import 'package:pshared/models/account/account.dart';
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
|
||||
extension AccountMapper on Account {
|
||||
AccountDTO toDTO() => AccountDTO(
|
||||
id: id,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
name: name,
|
||||
avatarUrl: avatarUrl,
|
||||
locale: locale,
|
||||
login: login,
|
||||
);
|
||||
}
|
||||
|
||||
extension AccountDTOMapper on AccountDTO {
|
||||
Account toDomain() => Account(
|
||||
storable: newStorable(id: id, createdAt: createdAt, updatedAt: updatedAt),
|
||||
avatarUrl: avatarUrl,
|
||||
locale: locale,
|
||||
login: login,
|
||||
name: name,
|
||||
);
|
||||
}
|
||||
24
frontend/pshared/lib/data/mapper/account/base.dart
Normal file
24
frontend/pshared/lib/data/mapper/account/base.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:pshared/data/dto/account/base.dart';
|
||||
import 'package:pshared/models/account/base.dart';
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
|
||||
extension AccountBaseMapper on AccountBase {
|
||||
AccountBaseDTO toDTO() => AccountBaseDTO(
|
||||
id: storable.id,
|
||||
createdAt: storable.createdAt,
|
||||
updatedAt: storable.updatedAt,
|
||||
avatarUrl: avatarUrl,
|
||||
name: name,
|
||||
locale: locale,
|
||||
);
|
||||
}
|
||||
|
||||
extension AccountDTOMapper on AccountBaseDTO {
|
||||
AccountBase toDomain() => AccountBase(
|
||||
storable: newStorable(id: id, createdAt: createdAt, updatedAt: updatedAt),
|
||||
avatarUrl: avatarUrl,
|
||||
name: name,
|
||||
locale: locale,
|
||||
);
|
||||
}
|
||||
164
frontend/pshared/lib/data/mapper/icon.dart
Normal file
164
frontend/pshared/lib/data/mapper/icon.dart
Normal file
@@ -0,0 +1,164 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
final Map<String, IconData> iconMapping = {
|
||||
// General Project Management Icons
|
||||
'dashboard': Icons.dashboard, // Overview screen
|
||||
'project': Icons.work, // Represents a project
|
||||
'tasks': Icons.check_box, // Task list
|
||||
'calendar': Icons.calendar_today, // Calendar view
|
||||
'team': Icons.group, // Team collaboration
|
||||
'kanban': Icons.view_column, // Kanban board
|
||||
'timeline': Icons.timeline, // Project timeline
|
||||
'milestone': Icons.flag, // Milestones
|
||||
'priority': Icons.priority_high, // General priority indicator
|
||||
'settings': Icons.settings, // Settings or configurations
|
||||
'chat': Icons.chat, // Communication/chat
|
||||
'files': Icons.insert_drive_file, // File management
|
||||
'notes': Icons.note, // Notes or documentation
|
||||
'report': Icons.insert_chart, // Reporting and analytics
|
||||
|
||||
// Priority Related Icons
|
||||
'to_do': Icons.assignment, // To do tasks
|
||||
'in_progress': Icons.autorenew, // Tasks in progress
|
||||
'complete': Icons.check_circle, // Completed tasks
|
||||
'archived': Icons.archive, // Archived tasks
|
||||
|
||||
// Deadline Related Icons
|
||||
'deadline': Icons.timer, // Deadline indicator
|
||||
'reminder': Icons.alarm, // Deadline reminder
|
||||
'due_today': Icons.today, // Tasks due today
|
||||
'upcoming': Icons.event_available, // Upcoming deadlines
|
||||
|
||||
// Additional
|
||||
'overdue': Icons.warning, // Overdue tasks or deadlines
|
||||
'budget': Icons.account_balance_wallet, // Budget and finance
|
||||
'resource': Icons.perm_contact_calendar, // Resource allocation
|
||||
'risk': Icons.warning_amber, // Risk management
|
||||
'feedback': Icons.feedback, // Feedback and reviews
|
||||
'timeline_edit': Icons.edit_calendar, // Edit project timeline
|
||||
'workflow': Icons.shuffle, // Workflow management
|
||||
'dependencies': Icons.link, // Task dependencies
|
||||
'progress': Icons.show_chart, // Project progress
|
||||
'schedule': Icons.schedule, // Scheduling
|
||||
'support': Icons.support, // Support/help
|
||||
'permissions': Icons.lock, // Access permissions
|
||||
'backup': Icons.backup, // Data backup
|
||||
'integration': Icons.extension, // Integrations
|
||||
'search': Icons.search, // Search functionality
|
||||
'announcement': Icons.announcement, // Announcements or updates
|
||||
'analytics': Icons.analytics, // Project analytics
|
||||
'assignment': Icons.assignment_turned_in, // Task assignments
|
||||
'discussions': Icons.forum, // Discussions/threads
|
||||
'timeline_view': Icons.view_timeline, // Detailed timeline view
|
||||
'board': Icons.dashboard_customize, // Custom project boards
|
||||
'approval': Icons.how_to_vote, // Approvals
|
||||
'review': Icons.rate_review, // Reviews and feedback
|
||||
'objective': Icons.golf_course, // Objectives/goals
|
||||
'settings_advanced': Icons.tune, // Advanced settings
|
||||
'time_tracking': Icons.timer_outlined, // Time tracking
|
||||
'checklist': Icons.checklist, // Checklists
|
||||
'sync': Icons.sync, // Syncing data
|
||||
'upload': Icons.cloud_upload, // Upload files
|
||||
'download': Icons.cloud_download, // Download files
|
||||
'share': Icons.share, // Sharing options
|
||||
'tag': Icons.label, // Tags/labels
|
||||
'notifications': Icons.notifications, // Notifications
|
||||
'user_roles': Icons.manage_accounts, // User roles and permissions
|
||||
'logout': Icons.logout, // Logout
|
||||
'automation': Icons.auto_awesome, // Automation
|
||||
'history': Icons.history, // Project history/logs
|
||||
'estimate': Icons.calculate, // Estimates and costing
|
||||
'quality': Icons.verified, // Quality assurance
|
||||
'strategy': Icons.lightbulb, // Strategy planning
|
||||
'feedback_form': Icons.comment, // Feedback forms
|
||||
'presentation': Icons.slideshow, // Project presentations
|
||||
};
|
||||
|
||||
|
||||
class ProjectIcons {
|
||||
static const IconData dashboard = Icons.dashboard;
|
||||
static const IconData project = Icons.work;
|
||||
static const IconData tasks = Icons.check_box;
|
||||
static const IconData calendar = Icons.calendar_today;
|
||||
static const IconData team = Icons.group;
|
||||
static const IconData kanban = Icons.view_column;
|
||||
static const IconData timeline = Icons.timeline;
|
||||
static const IconData milestone = Icons.flag;
|
||||
static const IconData priority = Icons.priority_high;
|
||||
static const IconData settings = Icons.settings;
|
||||
static const IconData chat = Icons.chat;
|
||||
static const IconData files = Icons.insert_drive_file;
|
||||
static const IconData notes = Icons.note;
|
||||
static const IconData report = Icons.insert_chart;
|
||||
static const IconData todo = Icons.assignment;
|
||||
static const IconData inProgress = Icons.autorenew;
|
||||
static const IconData complete = Icons.check_circle;
|
||||
static const IconData archived = Icons.archive;
|
||||
static const IconData deadline = Icons.timer;
|
||||
static const IconData reminder = Icons.alarm;
|
||||
static const IconData dueToday = Icons.today;
|
||||
static const IconData upcoming = Icons.event_available;
|
||||
static const IconData overdue = Icons.warning;
|
||||
static const IconData budget = Icons.account_balance_wallet;
|
||||
static const IconData resource = Icons.perm_contact_calendar;
|
||||
static const IconData risk = Icons.warning_amber;
|
||||
static const IconData feedback = Icons.feedback;
|
||||
static const IconData timelineEdit = Icons.edit_calendar;
|
||||
static const IconData workflow = Icons.shuffle;
|
||||
static const IconData dependencies = Icons.link;
|
||||
static const IconData progress = Icons.show_chart;
|
||||
static const IconData schedule = Icons.schedule;
|
||||
static const IconData support = Icons.support;
|
||||
static const IconData permissions = Icons.lock;
|
||||
static const IconData backup = Icons.backup;
|
||||
static const IconData integration = Icons.extension;
|
||||
static const IconData search = Icons.search;
|
||||
static const IconData announcement = Icons.announcement;
|
||||
static const IconData analytics = Icons.analytics;
|
||||
static const IconData assignment = Icons.assignment_turned_in;
|
||||
static const IconData discussions = Icons.forum;
|
||||
static const IconData timelineView = Icons.view_timeline;
|
||||
static const IconData board = Icons.dashboard_customize;
|
||||
static const IconData approval = Icons.how_to_vote;
|
||||
static const IconData review = Icons.rate_review;
|
||||
static const IconData objective = Icons.golf_course;
|
||||
static const IconData settingsAdvanced = Icons.tune;
|
||||
static const IconData timeTracking = Icons.timer_outlined;
|
||||
static const IconData checklist = Icons.checklist;
|
||||
static const IconData sync = Icons.sync;
|
||||
static const IconData upload = Icons.cloud_upload;
|
||||
static const IconData download = Icons.cloud_download;
|
||||
static const IconData share = Icons.share;
|
||||
static const IconData tag = Icons.label;
|
||||
static const IconData notifications = Icons.notifications;
|
||||
static const IconData userRoles = Icons.manage_accounts;
|
||||
static const IconData logout = Icons.logout;
|
||||
static const IconData automation = Icons.auto_awesome;
|
||||
static const IconData history = Icons.history;
|
||||
static const IconData estimate = Icons.calculate;
|
||||
static const IconData quality = Icons.verified;
|
||||
static const IconData strategy = Icons.lightbulb;
|
||||
static const IconData feedbackForm = Icons.comment;
|
||||
static const IconData presentation = Icons.slideshow;
|
||||
}
|
||||
|
||||
|
||||
extension IconDataKeyExtension on IconData {
|
||||
String get toIconKey {
|
||||
return iconMapping.entries.firstWhere(
|
||||
(entry) => entry.value == this,
|
||||
orElse: () => throw Exception('IconData not found in mapping.'),
|
||||
).key;
|
||||
}
|
||||
}
|
||||
|
||||
extension IconDataFromKeyExtension on String {
|
||||
IconData get toIconData {
|
||||
final iconData = iconMapping[this];
|
||||
if (iconData == null) {
|
||||
throw Exception('No IconData found for key: $this');
|
||||
}
|
||||
return iconData;
|
||||
}
|
||||
}
|
||||
22
frontend/pshared/lib/data/mapper/organization.dart
Normal file
22
frontend/pshared/lib/data/mapper/organization.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:pshared/data/dto/organization.dart';
|
||||
import 'package:pshared/models/organization/organization.dart';
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
|
||||
extension OrganizationMapper on Organization {
|
||||
OrganizationDTO toDTO() => OrganizationDTO(
|
||||
id: storable.id,
|
||||
createdAt: storable.createdAt,
|
||||
updatedAt: storable.updatedAt,
|
||||
timeZone: timeZone,
|
||||
logoUrl: logoUrl,
|
||||
);
|
||||
}
|
||||
|
||||
extension OrganizationDTOMapper on OrganizationDTO {
|
||||
Organization toDomain() => Organization(
|
||||
storable: newStorable(id: id, createdAt: createdAt, updatedAt: updatedAt),
|
||||
timeZone: timeZone,
|
||||
logoUrl: logoUrl,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'package:pshared/data/dto/organization/description.dart';
|
||||
import 'package:pshared/models/organization/description.dart';
|
||||
|
||||
|
||||
extension OrganizationDescriptionMapper on OrganizationDescription {
|
||||
OrganizationDescriptionDTO toDTO() => OrganizationDescriptionDTO(
|
||||
logoUrl: logoUrl,
|
||||
);
|
||||
}
|
||||
|
||||
extension AccountDescriptionDTOMapper on OrganizationDescriptionDTO {
|
||||
OrganizationDescription toDomain() => OrganizationDescription(
|
||||
logoUrl: logoUrl,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:pshared/data/dto/permissions/action_effect.dart';
|
||||
import 'package:pshared/models/permissions/action_effect.dart';
|
||||
import 'package:pshared/models/permissions/action.dart';
|
||||
import 'package:pshared/models/permissions/effect.dart';
|
||||
|
||||
|
||||
extension ActionEffectMapper on ActionEffect {
|
||||
ActionEffectDTO toDTO() {
|
||||
return ActionEffectDTO(
|
||||
action: action.toShortString(),
|
||||
effect: effect.toShortString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension ActionEffectDTOMapper on ActionEffectDTO {
|
||||
ActionEffect toDomain() {
|
||||
return ActionEffect(
|
||||
action: ActionExtension.fromString(action),
|
||||
effect: EffectExtension.fromString(effect),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import 'package:pshared/data/dto/permissions/data/permission.dart';
|
||||
import 'package:pshared/data/mapper/permissions/action_effect.dart';
|
||||
import 'package:pshared/models/permissions/data/permission.dart';
|
||||
import 'package:pshared/models/permissions/data/policy.dart';
|
||||
|
||||
|
||||
extension PermissionMapper on Permission {
|
||||
PermissionDTO toDTO() {
|
||||
return PermissionDTO(
|
||||
roleDescriptionRef: policy.roleDescriptionRef,
|
||||
organizationRef: policy.organizationRef,
|
||||
descriptionRef: policy.descriptionRef,
|
||||
objectRef: policy.objectRef,
|
||||
effect: policy.effect.toDTO(),
|
||||
accountRef: accountRef,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension PermissionDTOMapper on PermissionDTO {
|
||||
Permission toDomain() {
|
||||
return Permission(
|
||||
policy: Policy(
|
||||
roleDescriptionRef: roleDescriptionRef,
|
||||
organizationRef: organizationRef,
|
||||
descriptionRef: descriptionRef,
|
||||
objectRef: objectRef,
|
||||
effect: effect.toDomain(),
|
||||
),
|
||||
accountRef: accountRef,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import 'package:pshared/data/dto/permissions/data/permissions.dart';
|
||||
import 'package:pshared/data/mapper/permissions/data/permission.dart';
|
||||
import 'package:pshared/data/mapper/permissions/data/policy.dart';
|
||||
import 'package:pshared/data/mapper/permissions/data/role.dart';
|
||||
import 'package:pshared/models/permissions/data/permissions.dart';
|
||||
|
||||
|
||||
extension PermissionsDataMapper on PermissionsData {
|
||||
PermissionsDataDTO toDTO() {
|
||||
return PermissionsDataDTO(
|
||||
roles: roles.map((role) => role.toDTO()).toList(),
|
||||
policies: policies.map((policy) => policy.toDTO()).toList(),
|
||||
permissions: permissions.map((permission) => permission.toDTO()).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension PermissionsDataDTOMapper on PermissionsDataDTO {
|
||||
PermissionsData toDomain() {
|
||||
return PermissionsData(
|
||||
roles: roles.map((role) => role.toDomain()).toList(),
|
||||
policies: policies.map((policy) => policy.toDomain()).toList(),
|
||||
permissions: permissions.map((permission) => permission.toDomain()).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import 'package:pshared/data/dto/permissions/data/policy.dart';
|
||||
import 'package:pshared/data/mapper/permissions/action_effect.dart';
|
||||
import 'package:pshared/models/permissions/data/policy.dart';
|
||||
|
||||
|
||||
extension PolicyMapper on Policy {
|
||||
PolicyDTO toDTO() {
|
||||
return PolicyDTO(
|
||||
roleDescriptionRef: roleDescriptionRef,
|
||||
organizationRef: organizationRef,
|
||||
descriptionRef: descriptionRef,
|
||||
objectRef: objectRef,
|
||||
effect: effect.toDTO(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension PolicyDTOMapper on PolicyDTO {
|
||||
Policy toDomain() {
|
||||
return Policy(
|
||||
roleDescriptionRef: roleDescriptionRef,
|
||||
organizationRef: organizationRef,
|
||||
descriptionRef: descriptionRef,
|
||||
objectRef: objectRef,
|
||||
effect: effect.toDomain(),
|
||||
);
|
||||
}
|
||||
}
|
||||
25
frontend/pshared/lib/data/mapper/permissions/data/role.dart
Normal file
25
frontend/pshared/lib/data/mapper/permissions/data/role.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:pshared/data/dto/permissions/data/role.dart';
|
||||
import 'package:pshared/models/permissions/data/role.dart';
|
||||
|
||||
|
||||
extension RoleMapper on Role {
|
||||
/// Converts a `Role` domain model to a `RoleDTO`.
|
||||
RoleDTO toDTO() {
|
||||
return RoleDTO(
|
||||
accountRef: accountRef,
|
||||
descriptionRef: descriptionRef,
|
||||
organizationRef: organizationRef,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension RoleDTOMapper on RoleDTO {
|
||||
/// Converts a `RoleDTO` to a `Role` domain model.
|
||||
Role toDomain() {
|
||||
return Role(
|
||||
accountRef: accountRef,
|
||||
descriptionRef: descriptionRef,
|
||||
organizationRef: organizationRef,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:pshared/data/dto/permissions/description/description.dart';
|
||||
import 'package:pshared/data/mapper/permissions/descriptions/policy.dart';
|
||||
import 'package:pshared/data/mapper/permissions/descriptions/role.dart';
|
||||
import 'package:pshared/models/permissions/descriptions/permissions.dart';
|
||||
|
||||
|
||||
extension PermissionsDescriptionMapper on PermissionsDescription {
|
||||
PermissionsDescriptionDTO toDTO() {
|
||||
return PermissionsDescriptionDTO(
|
||||
roles: roles.map((role) => role.toDTO()).toList(),
|
||||
policies: policies.map((policy) => policy.toDTO()).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension PermissionsDescriptionDTOMapper on PermissionsDescriptionDTO {
|
||||
PermissionsDescription toDomain() {
|
||||
return PermissionsDescription(
|
||||
roles: roles.map((role) => role.toDomain()).toList(),
|
||||
policies: policies.map((policy) => policy.toDomain()).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'package:pshared/data/dto/permissions/description/policy.dart';
|
||||
import 'package:pshared/models/permissions/descriptions/policy.dart';
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
|
||||
extension PolicyDescriptionMapper on PolicyDescription {
|
||||
PolicyDescriptionDTO toDTO() => PolicyDescriptionDTO(
|
||||
id: storable.id,
|
||||
createdAt: storable.createdAt,
|
||||
updatedAt: storable.updatedAt,
|
||||
resourceTypes: resourceTypes,
|
||||
organizationRef: organizationRef,
|
||||
);
|
||||
}
|
||||
|
||||
extension PolicyDescriptionDTOMapper on PolicyDescriptionDTO {
|
||||
PolicyDescription toDomain() => PolicyDescription(
|
||||
storable: newStorable(id: id, createdAt: createdAt, updatedAt: createdAt),
|
||||
resourceTypes: resourceTypes,
|
||||
organizationRef: organizationRef,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import 'package:pshared/data/dto/permissions/description/role.dart';
|
||||
import 'package:pshared/models/permissions/descriptions/role.dart';
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
|
||||
extension RoleDescriptionMapper on RoleDescription {
|
||||
RoleDescriptionDTO toDTO() => RoleDescriptionDTO(
|
||||
id: storable.id,
|
||||
createdAt: storable.createdAt,
|
||||
updatedAt: storable.updatedAt,
|
||||
organizationRef: organizationRef,
|
||||
);
|
||||
}
|
||||
|
||||
extension RoleDescriptionDTOMapper on RoleDescriptionDTO {
|
||||
RoleDescription toDomain() => RoleDescription(
|
||||
storable: newStorable(id: id, createdAt: createdAt, updatedAt: updatedAt),
|
||||
organizationRef: organizationRef,
|
||||
);
|
||||
}
|
||||
11
frontend/pshared/lib/data/mapper/storable.dart
Normal file
11
frontend/pshared/lib/data/mapper/storable.dart
Normal file
@@ -0,0 +1,11 @@
|
||||
import 'package:pshared/data/dto/storable.dart';
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
|
||||
extension StorableMapper on Storable {
|
||||
StorableDTO toDTO() => StorableDTO(id: id, createdAt: createdAt, updatedAt: updatedAt);
|
||||
}
|
||||
|
||||
extension StorableDTOMapper on StorableDTO {
|
||||
Storable toDomain() => newStorable(id: id, createdAt: createdAt, updatedAt: updatedAt);
|
||||
}
|
||||
23
frontend/pshared/lib/l10n/ps_en.arb
Normal file
23
frontend/pshared/lib/l10n/ps_en.arb
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"@@locale": "en",
|
||||
|
||||
"statusReady": "Ready",
|
||||
"statusRegistered": "Registered",
|
||||
"statusNotRegistered": "Not Registered",
|
||||
"typeInternal": "Internal",
|
||||
"typeExternal": "External",
|
||||
"operationStatusProcessing": "Processing",
|
||||
"@operationStatusProcessing": {
|
||||
"description": "Label for the “processing” operation status"
|
||||
},
|
||||
|
||||
"operationStatusSuccess": "Success",
|
||||
"@operationStatusSuccess": {
|
||||
"description": "Label for the “success” operation status"
|
||||
},
|
||||
|
||||
"operationStatusError": "Error",
|
||||
"@operationStatusError": {
|
||||
"description": "Label for the “error” operation status"
|
||||
}
|
||||
}
|
||||
36
frontend/pshared/lib/models/account/account.dart
Normal file
36
frontend/pshared/lib/models/account/account.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'package:pshared/models/account/base.dart';
|
||||
|
||||
|
||||
class Account extends AccountBase {
|
||||
final String login;
|
||||
|
||||
const Account({
|
||||
required super.storable,
|
||||
required super.avatarUrl,
|
||||
required this.login,
|
||||
required super.locale,
|
||||
required super.name,
|
||||
});
|
||||
|
||||
factory Account.fromBase(AccountBase accountBase, String login) => Account(
|
||||
storable: accountBase.storable,
|
||||
avatarUrl: accountBase.avatarUrl,
|
||||
locale: accountBase.locale,
|
||||
name: accountBase.name,
|
||||
login: login,
|
||||
);
|
||||
|
||||
@override
|
||||
Account copyWith({
|
||||
String? Function()? avatarUrl,
|
||||
String? name,
|
||||
String? locale,
|
||||
}) {
|
||||
final updatedBase = super.copyWith(
|
||||
avatarUrl: avatarUrl,
|
||||
name: name,
|
||||
locale: locale,
|
||||
);
|
||||
return Account.fromBase(updatedBase, login);
|
||||
}
|
||||
}
|
||||
35
frontend/pshared/lib/models/account/base.dart
Normal file
35
frontend/pshared/lib/models/account/base.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
|
||||
class AccountBase implements Storable {
|
||||
final Storable storable;
|
||||
|
||||
@override
|
||||
String get id => storable.id;
|
||||
@override
|
||||
DateTime get createdAt => storable.createdAt;
|
||||
@override
|
||||
DateTime get updatedAt => storable.updatedAt;
|
||||
|
||||
final String? avatarUrl;
|
||||
final String name;
|
||||
final String locale;
|
||||
|
||||
const AccountBase({
|
||||
required this.storable,
|
||||
required this.name,
|
||||
required this.locale,
|
||||
required this.avatarUrl,
|
||||
});
|
||||
|
||||
AccountBase copyWith({
|
||||
String? Function()? avatarUrl,
|
||||
String? name,
|
||||
String? locale,
|
||||
}) => AccountBase(
|
||||
storable: storable,
|
||||
avatarUrl: avatarUrl != null ? avatarUrl() : this.avatarUrl,
|
||||
locale: locale ?? this.locale,
|
||||
name: name ?? this.name,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class OrganizationDescription {
|
||||
final String? logoUrl;
|
||||
|
||||
const OrganizationDescription({
|
||||
this.logoUrl,
|
||||
});
|
||||
}
|
||||
4
frontend/pshared/lib/models/organization/employee.dart
Normal file
4
frontend/pshared/lib/models/organization/employee.dart
Normal file
@@ -0,0 +1,4 @@
|
||||
import 'package:pshared/models/account/account.dart';
|
||||
|
||||
|
||||
typedef Employee = Account;
|
||||
34
frontend/pshared/lib/models/organization/organization.dart
Normal file
34
frontend/pshared/lib/models/organization/organization.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
|
||||
class Organization implements Storable {
|
||||
final Storable storable;
|
||||
|
||||
@override
|
||||
String get id => storable.id;
|
||||
@override
|
||||
DateTime get createdAt => storable.createdAt;
|
||||
@override
|
||||
DateTime get updatedAt => storable.updatedAt;
|
||||
|
||||
final String timeZone;
|
||||
final String? logoUrl;
|
||||
|
||||
const Organization({
|
||||
required this.storable,
|
||||
required this.timeZone,
|
||||
this.logoUrl,
|
||||
});
|
||||
|
||||
|
||||
Organization copyWith({
|
||||
String? name,
|
||||
String? Function()? description,
|
||||
String? timeZone,
|
||||
String? Function()? logoUrl,
|
||||
}) => Organization(
|
||||
storable: storable, // Same Storable, same id
|
||||
timeZone: timeZone ?? this.timeZone,
|
||||
logoUrl: logoUrl != null ? logoUrl() : this.logoUrl,
|
||||
);
|
||||
}
|
||||
18
frontend/pshared/lib/models/payment/methods/card.dart
Normal file
18
frontend/pshared/lib/models/payment/methods/card.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class CardPaymentMethod extends PaymentMethodData {
|
||||
@override
|
||||
final PaymentType type = PaymentType.card;
|
||||
|
||||
final String pan;
|
||||
final String firstName;
|
||||
final String lastName;
|
||||
|
||||
CardPaymentMethod({
|
||||
required this.pan,
|
||||
required this.firstName,
|
||||
required this.lastName,
|
||||
});
|
||||
}
|
||||
6
frontend/pshared/lib/models/payment/methods/data.dart
Normal file
6
frontend/pshared/lib/models/payment/methods/data.dart
Normal file
@@ -0,0 +1,6 @@
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
abstract class PaymentMethodData {
|
||||
PaymentType get type;
|
||||
}
|
||||
20
frontend/pshared/lib/models/payment/methods/iban.dart
Normal file
20
frontend/pshared/lib/models/payment/methods/iban.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class IbanPaymentMethod extends PaymentMethodData {
|
||||
@override
|
||||
final PaymentType type = PaymentType.iban;
|
||||
|
||||
final String iban; // e.g. DE89 3704 0044 0532 0130 00
|
||||
final String accountHolder; // Full name of the recipient
|
||||
final String? bic; // Optional: for cross-border transfers
|
||||
final String? bankName; // Optional: for UI clarity
|
||||
|
||||
IbanPaymentMethod({
|
||||
required this.iban,
|
||||
required this.accountHolder,
|
||||
this.bic,
|
||||
this.bankName,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class RussianBankAccountPaymentMethod extends PaymentMethodData {
|
||||
@override
|
||||
final PaymentType type = PaymentType.bankAccount;
|
||||
|
||||
final String recipientName;
|
||||
final String inn;
|
||||
final String kpp;
|
||||
final String bankName;
|
||||
final String bik;
|
||||
final String accountNumber;
|
||||
final String correspondentAccount;
|
||||
|
||||
RussianBankAccountPaymentMethod({
|
||||
required this.recipientName,
|
||||
required this.inn,
|
||||
required this.kpp,
|
||||
required this.bankName,
|
||||
required this.bik,
|
||||
required this.accountNumber,
|
||||
required this.correspondentAccount,
|
||||
});
|
||||
}
|
||||
21
frontend/pshared/lib/models/payment/methods/type.dart
Normal file
21
frontend/pshared/lib/models/payment/methods/type.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class PaymentMethod {
|
||||
PaymentMethod({
|
||||
required this.id,
|
||||
required this.label,
|
||||
required this.details,
|
||||
required this.type,
|
||||
this.isEnabled = true,
|
||||
this.isMain = false,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String label;
|
||||
final String details;
|
||||
final PaymentType type;
|
||||
|
||||
bool isEnabled;
|
||||
bool isMain;
|
||||
}
|
||||
12
frontend/pshared/lib/models/payment/methods/wallet.dart
Normal file
12
frontend/pshared/lib/models/payment/methods/wallet.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class WalletPaymentMethod extends PaymentMethodData {
|
||||
@override
|
||||
final PaymentType type = PaymentType.wallet;
|
||||
|
||||
final String walletId;
|
||||
|
||||
WalletPaymentMethod({required this.walletId});
|
||||
}
|
||||
30
frontend/pshared/lib/models/payment/operation.dart
Normal file
30
frontend/pshared/lib/models/payment/operation.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'package:pshared/models/payment/status.dart';
|
||||
|
||||
|
||||
class OperationItem {
|
||||
final OperationStatus status;
|
||||
final String? fileName;
|
||||
final double amount;
|
||||
final String currency;
|
||||
final double toAmount;
|
||||
final String toCurrency;
|
||||
final String payId;
|
||||
final String? cardNumber;
|
||||
final String name;
|
||||
final DateTime date;
|
||||
final String comment;
|
||||
|
||||
OperationItem({
|
||||
required this.status,
|
||||
this.fileName,
|
||||
required this.amount,
|
||||
required this.currency,
|
||||
required this.toAmount,
|
||||
required this.toCurrency,
|
||||
required this.payId,
|
||||
this.cardNumber,
|
||||
required this.name,
|
||||
required this.date,
|
||||
required this.comment,
|
||||
});
|
||||
}
|
||||
25
frontend/pshared/lib/models/payment/status.dart
Normal file
25
frontend/pshared/lib/models/payment/status.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:pshared/generated/i18n/ps_localizations.dart';
|
||||
|
||||
enum OperationStatus {
|
||||
processing,
|
||||
success,
|
||||
error,
|
||||
}
|
||||
|
||||
|
||||
extension OperationStatusX on OperationStatus {
|
||||
/// Returns the localized string for this status,
|
||||
/// e.g. “Processing”, “Success”, “Error”.
|
||||
String localized(BuildContext context) {
|
||||
final loc = PSLocalizations.of(context)!;
|
||||
switch (this) {
|
||||
case OperationStatus.processing:
|
||||
return loc.operationStatusProcessing;
|
||||
case OperationStatus.success:
|
||||
return loc.operationStatusSuccess;
|
||||
case OperationStatus.error:
|
||||
return loc.operationStatusError;
|
||||
}
|
||||
}
|
||||
}
|
||||
6
frontend/pshared/lib/models/payment/type.dart
Normal file
6
frontend/pshared/lib/models/payment/type.dart
Normal file
@@ -0,0 +1,6 @@
|
||||
enum PaymentType {
|
||||
bankAccount,
|
||||
iban,
|
||||
wallet,
|
||||
card,
|
||||
}
|
||||
11
frontend/pshared/lib/models/payment/upload_history_item.dart
Normal file
11
frontend/pshared/lib/models/payment/upload_history_item.dart
Normal file
@@ -0,0 +1,11 @@
|
||||
class UploadHistoryItem {
|
||||
final String name;
|
||||
final String status;
|
||||
final String time;
|
||||
|
||||
UploadHistoryItem({
|
||||
required this.name,
|
||||
required this.status,
|
||||
required this.time,
|
||||
});
|
||||
}
|
||||
22
frontend/pshared/lib/models/permission_bound.dart
Normal file
22
frontend/pshared/lib/models/permission_bound.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:pshared/config/constants.dart';
|
||||
|
||||
|
||||
abstract class PermissionBound {
|
||||
String get permissionRef;
|
||||
String get organizationRef;
|
||||
}
|
||||
|
||||
class _PermissionBoundImp implements PermissionBound {
|
||||
@override
|
||||
final String permissionRef;
|
||||
@override
|
||||
final String organizationRef;
|
||||
|
||||
const _PermissionBoundImp({
|
||||
required this.permissionRef,
|
||||
required this.organizationRef,
|
||||
});
|
||||
}
|
||||
|
||||
PermissionBound newPermissionBound({ required String organizationRef, String? permissionRef}) =>
|
||||
_PermissionBoundImp(permissionRef: permissionRef ?? Constants.nilObjectRef, organizationRef: organizationRef);
|
||||
@@ -0,0 +1,6 @@
|
||||
import 'package:pshared/models/permission_bound.dart';
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
|
||||
abstract class PermissionBoundStorable implements PermissionBound, Storable {
|
||||
}
|
||||
13
frontend/pshared/lib/models/permissions/access.dart
Normal file
13
frontend/pshared/lib/models/permissions/access.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:pshared/models/permissions/data/permissions.dart';
|
||||
import 'package:pshared/models/permissions/descriptions/permissions.dart';
|
||||
|
||||
|
||||
class UserAccess {
|
||||
final PermissionsDescription descriptions;
|
||||
final PermissionsData permissions;
|
||||
|
||||
const UserAccess({
|
||||
required this.descriptions,
|
||||
required this.permissions,
|
||||
});
|
||||
}
|
||||
15
frontend/pshared/lib/models/permissions/action.dart
Normal file
15
frontend/pshared/lib/models/permissions/action.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
enum Action {
|
||||
create,
|
||||
read,
|
||||
update,
|
||||
delete,
|
||||
}
|
||||
|
||||
extension ActionExtension on Action {
|
||||
String toShortString() => toString().split('.').last;
|
||||
|
||||
static Action fromString(String value) => Action.values.firstWhere(
|
||||
(e) => e.toShortString() == value,
|
||||
orElse: () => throw ArgumentError('Invalid action: $value'),
|
||||
);
|
||||
}
|
||||
13
frontend/pshared/lib/models/permissions/action_effect.dart
Normal file
13
frontend/pshared/lib/models/permissions/action_effect.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:pshared/models/permissions/action.dart';
|
||||
import 'package:pshared/models/permissions/effect.dart';
|
||||
|
||||
|
||||
class ActionEffect {
|
||||
final Action action; // The action allowed or denied
|
||||
final Effect effect; // The effect of the policy ("allow" or "deny")
|
||||
|
||||
const ActionEffect({
|
||||
required this.action,
|
||||
required this.effect,
|
||||
});
|
||||
}
|
||||
12
frontend/pshared/lib/models/permissions/data/permission.dart
Normal file
12
frontend/pshared/lib/models/permissions/data/permission.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
import 'package:pshared/models/permissions/data/policy.dart';
|
||||
|
||||
|
||||
class Permission {
|
||||
final Policy policy;
|
||||
final String accountRef;
|
||||
|
||||
const Permission({
|
||||
required this.policy,
|
||||
required this.accountRef,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import 'package:pshared/models/permissions/data/permission.dart';
|
||||
import 'package:pshared/models/permissions/data/policy.dart';
|
||||
import 'package:pshared/models/permissions/data/role.dart';
|
||||
|
||||
|
||||
class PermissionsData {
|
||||
final List<Role> roles;
|
||||
final List<Policy> policies;
|
||||
final List<Permission> permissions;
|
||||
|
||||
const PermissionsData({
|
||||
required this.roles,
|
||||
required this.policies,
|
||||
required this.permissions,
|
||||
});
|
||||
}
|
||||
18
frontend/pshared/lib/models/permissions/data/policy.dart
Normal file
18
frontend/pshared/lib/models/permissions/data/policy.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:pshared/models/permissions/action_effect.dart';
|
||||
|
||||
|
||||
class Policy {
|
||||
final String roleDescriptionRef;
|
||||
final String organizationRef;
|
||||
final String descriptionRef;
|
||||
final String? objectRef;
|
||||
final ActionEffect effect;
|
||||
|
||||
const Policy({
|
||||
required this.roleDescriptionRef,
|
||||
required this.organizationRef,
|
||||
required this.descriptionRef,
|
||||
required this.objectRef,
|
||||
required this.effect,
|
||||
});
|
||||
}
|
||||
11
frontend/pshared/lib/models/permissions/data/role.dart
Normal file
11
frontend/pshared/lib/models/permissions/data/role.dart
Normal file
@@ -0,0 +1,11 @@
|
||||
class Role {
|
||||
final String accountRef;
|
||||
final String organizationRef;
|
||||
final String descriptionRef;
|
||||
|
||||
const Role({
|
||||
required this.accountRef,
|
||||
required this.descriptionRef,
|
||||
required this.organizationRef,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import 'package:pshared/models/permissions/descriptions/policy.dart';
|
||||
import 'package:pshared/models/permissions/descriptions/role.dart';
|
||||
|
||||
|
||||
class PermissionsDescription {
|
||||
final List<RoleDescription> roles;
|
||||
final List<PolicyDescription> policies;
|
||||
|
||||
const PermissionsDescription({
|
||||
required this.roles,
|
||||
required this.policies,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'package:pshared/models/resources.dart';
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
|
||||
class PolicyDescription implements Storable {
|
||||
final Storable storable;
|
||||
final List<ResourceType>? resourceTypes;
|
||||
final String? organizationRef;
|
||||
|
||||
@override
|
||||
String get id => storable.id;
|
||||
@override
|
||||
DateTime get createdAt => storable.createdAt;
|
||||
@override
|
||||
DateTime get updatedAt => storable.updatedAt;
|
||||
|
||||
const PolicyDescription({
|
||||
required this.storable,
|
||||
required this.resourceTypes,
|
||||
required this.organizationRef,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
|
||||
class RoleDescription implements Storable {
|
||||
final Storable storable;
|
||||
|
||||
@override
|
||||
String get id => storable.id;
|
||||
@override
|
||||
DateTime get createdAt => storable.createdAt;
|
||||
@override
|
||||
DateTime get updatedAt => storable.updatedAt;
|
||||
|
||||
final String organizationRef;
|
||||
|
||||
const RoleDescription({
|
||||
required this.storable,
|
||||
required this.organizationRef,
|
||||
});
|
||||
|
||||
factory RoleDescription.build({
|
||||
required String organizationRef,
|
||||
}) => RoleDescription(
|
||||
storable: newStorable(),
|
||||
organizationRef: organizationRef
|
||||
);
|
||||
}
|
||||
13
frontend/pshared/lib/models/permissions/effect.dart
Normal file
13
frontend/pshared/lib/models/permissions/effect.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
enum Effect {
|
||||
allow,
|
||||
deny,
|
||||
}
|
||||
|
||||
extension EffectExtension on Effect {
|
||||
String toShortString() => toString().split('.').last;
|
||||
|
||||
static Effect fromString(String value) => Effect.values.firstWhere(
|
||||
(e) => e.toShortString() == value,
|
||||
orElse: () => throw ArgumentError('Invalid effect: $value'),
|
||||
);
|
||||
}
|
||||
0
frontend/pshared/lib/models/pfe/services.dart
Normal file
0
frontend/pshared/lib/models/pfe/services.dart
Normal file
1
frontend/pshared/lib/models/recipient/filter.dart
Normal file
1
frontend/pshared/lib/models/recipient/filter.dart
Normal file
@@ -0,0 +1 @@
|
||||
enum RecipientFilter { all, ready, registered, notRegistered }
|
||||
78
frontend/pshared/lib/models/recipient/recipient.dart
Normal file
78
frontend/pshared/lib/models/recipient/recipient.dart
Normal file
@@ -0,0 +1,78 @@
|
||||
import 'package:pshared/models/payment/methods/card.dart';
|
||||
import 'package:pshared/models/payment/methods/iban.dart';
|
||||
import 'package:pshared/models/payment/methods/russian_bank.dart';
|
||||
import 'package:pshared/models/payment/methods/wallet.dart';
|
||||
import 'package:pshared/models/recipient/status.dart';
|
||||
import 'package:pshared/models/recipient/type.dart';
|
||||
|
||||
|
||||
class Recipient {
|
||||
final String? avatarUrl; // network URL / local asset
|
||||
final String name;
|
||||
final String email;
|
||||
final RecipientStatus status;
|
||||
final RecipientType type;
|
||||
final CardPaymentMethod? card;
|
||||
final IbanPaymentMethod? iban;
|
||||
final RussianBankAccountPaymentMethod? bank;
|
||||
final WalletPaymentMethod? wallet;
|
||||
|
||||
const Recipient({
|
||||
this.avatarUrl,
|
||||
required this.name,
|
||||
required this.email,
|
||||
required this.status,
|
||||
required this.type,
|
||||
this.card,
|
||||
this.iban,
|
||||
this.bank,
|
||||
this.wallet,
|
||||
});
|
||||
|
||||
/// Convenience factory for quickly creating mock recipients.
|
||||
factory Recipient.mock({
|
||||
required String name,
|
||||
required String email,
|
||||
required RecipientStatus status,
|
||||
required RecipientType type,
|
||||
CardPaymentMethod? card,
|
||||
IbanPaymentMethod? iban,
|
||||
RussianBankAccountPaymentMethod? bank,
|
||||
WalletPaymentMethod? wallet,
|
||||
}) =>
|
||||
Recipient(
|
||||
avatarUrl: null,
|
||||
name: name,
|
||||
email: email,
|
||||
status: status,
|
||||
type: type,
|
||||
card: card,
|
||||
iban: iban,
|
||||
bank: bank,
|
||||
wallet: wallet,
|
||||
);
|
||||
|
||||
bool matchesQuery(String q) {
|
||||
final searchable = [
|
||||
name,
|
||||
email,
|
||||
card?.pan,
|
||||
card?.firstName,
|
||||
card?.lastName,
|
||||
iban?.iban,
|
||||
iban?.accountHolder,
|
||||
iban?.bic,
|
||||
iban?.bankName,
|
||||
bank?.accountNumber,
|
||||
bank?.recipientName,
|
||||
bank?.inn,
|
||||
bank?.kpp,
|
||||
bank?.bankName,
|
||||
bank?.bik,
|
||||
bank?.correspondentAccount,
|
||||
wallet?.walletId,
|
||||
];
|
||||
|
||||
return searchable.any((field) => field?.toLowerCase().contains(q) ?? false);
|
||||
}
|
||||
}
|
||||
22
frontend/pshared/lib/models/recipient/status.dart
Normal file
22
frontend/pshared/lib/models/recipient/status.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:pshared/generated/i18n/ps_localizations.dart';
|
||||
|
||||
|
||||
/// Possible payout readiness states.
|
||||
enum RecipientStatus { ready, registered, notRegistered }
|
||||
|
||||
extension RecipientStatusExtension on RecipientStatus {
|
||||
/// Human-readable, **localized** label for display in the UI.
|
||||
String label(BuildContext context) {
|
||||
final l10n = PSLocalizations.of(context)!;
|
||||
switch (this) {
|
||||
case RecipientStatus.ready:
|
||||
return l10n.statusReady;
|
||||
case RecipientStatus.registered:
|
||||
return l10n.statusRegistered;
|
||||
case RecipientStatus.notRegistered:
|
||||
return l10n.statusNotRegistered;
|
||||
}
|
||||
}
|
||||
}
|
||||
15
frontend/pshared/lib/models/recipient/type.dart
Normal file
15
frontend/pshared/lib/models/recipient/type.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:pshared/generated/i18n/ps_localizations.dart';
|
||||
|
||||
|
||||
/// Indicates whether you (internal) or the other party (external) manage payout data.
|
||||
enum RecipientType { internal, external }
|
||||
|
||||
extension RecipientTypeExtension on RecipientType {
|
||||
/// Localized label – no opaque abbreviations.
|
||||
String label(BuildContext context) =>
|
||||
this == RecipientType.internal
|
||||
? PSLocalizations.of(context)!.typeInternal
|
||||
: PSLocalizations.of(context)!.typeExternal;
|
||||
}
|
||||
107
frontend/pshared/lib/models/resources.dart
Normal file
107
frontend/pshared/lib/models/resources.dart
Normal file
@@ -0,0 +1,107 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
/// Represents various resource types (mirroring your Go "Type" constants).
|
||||
enum ResourceType {
|
||||
/// Represents user accounts in the system
|
||||
@JsonValue('accounts')
|
||||
accounts,
|
||||
|
||||
/// Represents analytics integration with Amplitude
|
||||
@JsonValue('amplitude')
|
||||
amplitude,
|
||||
|
||||
/// Represents automation workflows
|
||||
@JsonValue('automations')
|
||||
automations,
|
||||
|
||||
/// Tracks changes made to resources
|
||||
@JsonValue('changes')
|
||||
changes,
|
||||
|
||||
/// Represents client information
|
||||
@JsonValue('clients')
|
||||
clients,
|
||||
|
||||
/// Represents comments on tasks or other resources
|
||||
@JsonValue('comments')
|
||||
comments,
|
||||
|
||||
/// Represents invitations sent to users
|
||||
@JsonValue('invitations')
|
||||
invitations,
|
||||
|
||||
/// Represents invoices
|
||||
@JsonValue('invoices')
|
||||
invoices,
|
||||
|
||||
/// Represents logos for organizations or projects
|
||||
@JsonValue('logo')
|
||||
logo,
|
||||
|
||||
/// Represents notifications sent to users
|
||||
@JsonValue('notifications')
|
||||
notifications,
|
||||
|
||||
/// Represents organizations in the system
|
||||
@JsonValue('organizations')
|
||||
organizations,
|
||||
|
||||
/// Represents permissions service
|
||||
@JsonValue('permissions')
|
||||
permissions,
|
||||
|
||||
/// Represents access control policies
|
||||
@JsonValue('policies')
|
||||
policies,
|
||||
|
||||
/// Represents task or project priorities
|
||||
@JsonValue('priorities')
|
||||
priorities,
|
||||
|
||||
/// Represents priority groups
|
||||
@JsonValue('priority_groups')
|
||||
priorityGroups,
|
||||
|
||||
/// Represents projects managed in the system
|
||||
@JsonValue('projects')
|
||||
projects,
|
||||
|
||||
@JsonValue('properties')
|
||||
properties,
|
||||
|
||||
/// Represents reactions
|
||||
@JsonValue('reactions')
|
||||
reactions,
|
||||
|
||||
/// Represents refresh tokens for authentication
|
||||
@JsonValue('refresh_tokens')
|
||||
refreshTokens,
|
||||
|
||||
/// Represents roles in access control
|
||||
@JsonValue('roles')
|
||||
roles,
|
||||
|
||||
/// Represents statuses of tasks or projects
|
||||
@JsonValue('statuses')
|
||||
statuses,
|
||||
|
||||
/// Represents steps in workflows or processes
|
||||
@JsonValue('steps')
|
||||
steps,
|
||||
|
||||
/// Represents tasks managed in the system
|
||||
@JsonValue('tasks')
|
||||
tasks,
|
||||
|
||||
/// Represents teams managed in the system
|
||||
@JsonValue('teams')
|
||||
teams,
|
||||
|
||||
/// Represents workflows for tasks or projects
|
||||
@JsonValue('workflows')
|
||||
workflows,
|
||||
|
||||
/// Represents workspaces containing projects and teams
|
||||
@JsonValue('workspaces')
|
||||
workspaces;
|
||||
}
|
||||
77
frontend/pshared/lib/models/settings/localizations.dart
Normal file
77
frontend/pshared/lib/models/settings/localizations.dart
Normal file
@@ -0,0 +1,77 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
typedef LangLocalization = Map<String, String>;
|
||||
|
||||
String _translation(LangLocalization loc, String key) {
|
||||
return loc[key] ?? '';
|
||||
}
|
||||
|
||||
typedef Localizations = Map<String, LangLocalization>;
|
||||
|
||||
typedef Localizer = String Function(BuildContext);
|
||||
|
||||
class Localization {
|
||||
|
||||
static const String keyHint = 'hint';
|
||||
static const String keyLink = 'link';
|
||||
static const String keyName = 'name';
|
||||
static const String keyError = 'error';
|
||||
static const String keyAddress = 'address';
|
||||
static const String keyDetails = 'details';
|
||||
static const String keyRoute = 'route';
|
||||
static const String keyLocationName = 'location_name';
|
||||
|
||||
static String _localizeImp(Localizations localizations, String locale, String Function(LangLocalization) functor) {
|
||||
final localization = localizations[locale];
|
||||
if (localization != null) {
|
||||
return functor(localization);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
static String _localize(Localizations localizations, String locale, String Function(LangLocalization) functor, {String? fallback}) {
|
||||
final res = _localizeImp(localizations, locale, functor);
|
||||
return res.isNotEmpty ? res : (fallback ?? '');
|
||||
}
|
||||
|
||||
static bool localizationExists(Localizations loc, String locale) {
|
||||
return loc.containsKey(locale);
|
||||
}
|
||||
|
||||
static String hint(Localizations loc, String locale, {String? fallback}) {
|
||||
return _localize(loc, locale, (localization) => _translation(localization, keyHint), fallback: fallback);
|
||||
}
|
||||
|
||||
static String link(Localizations loc, String locale, {String? fallback}) {
|
||||
return _localize(loc, locale, (localization) => _translation(localization, keyLink), fallback: fallback);
|
||||
}
|
||||
|
||||
static String name(Localizations loc, String locale, {String? fallback}) {
|
||||
return _localize(loc, locale, (localization) => _translation(localization, keyName), fallback: fallback);
|
||||
}
|
||||
|
||||
static String error(Localizations loc, String locale, {String? fallback}) {
|
||||
return _localize(loc, locale, (localization) => _translation(localization, keyError), fallback: fallback);
|
||||
}
|
||||
|
||||
static String address(Localizations loc, String locale, {String? fallback}) {
|
||||
return _localize(loc, locale, (localization) => _translation(localization, keyAddress), fallback: fallback);
|
||||
}
|
||||
|
||||
static String details(Localizations loc, String locale, {String? fallback}) {
|
||||
return _localize(loc, locale, (localization) => _translation(localization, keyDetails), fallback: fallback);
|
||||
}
|
||||
|
||||
static String route(Localizations loc, String locale, {String? fallback}) {
|
||||
return _localize(loc, locale, (localization) => _translation(localization, keyRoute), fallback: fallback);
|
||||
}
|
||||
|
||||
static String locationName(Localizations loc, String locale, {String? fallback}) {
|
||||
return _localize(loc, locale, (localization) => _translation(localization, keyLocationName), fallback: fallback);
|
||||
}
|
||||
|
||||
static String translate(Localizations loc, String locale, String key, {String? fallback}) {
|
||||
return _localize(loc, locale, (localization) => _translation(localization, key), fallback: fallback);
|
||||
}
|
||||
}
|
||||
27
frontend/pshared/lib/models/settings/time_validity.dart
Normal file
27
frontend/pshared/lib/models/settings/time_validity.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'time_validity.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class TimeValidity {
|
||||
final DateTime? start;
|
||||
final DateTime? expiry;
|
||||
|
||||
const TimeValidity({this.start, this.expiry});
|
||||
|
||||
bool get isExpired => expiry?.isBefore(DateTime.now()) ?? false;
|
||||
bool get isNotStarted => start?.isAfter(DateTime.now()) ?? false;
|
||||
bool get isActive => (!isNotStarted) && (!isExpired);
|
||||
|
||||
TimeValidity copyWith({
|
||||
DateTime? Function()? start,
|
||||
DateTime? Function()? expiry,
|
||||
}) => TimeValidity(
|
||||
start: start == null ? this.start : start(),
|
||||
expiry: expiry == null ? this.expiry : expiry(),
|
||||
);
|
||||
|
||||
factory TimeValidity.fromJson(Map<String, dynamic> json) => _$TimeValidityFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$TimeValidityToJson(this);
|
||||
}
|
||||
30
frontend/pshared/lib/models/storable.dart
Normal file
30
frontend/pshared/lib/models/storable.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'package:pshared/config/constants.dart';
|
||||
|
||||
|
||||
abstract class Storable {
|
||||
String get id;
|
||||
DateTime get createdAt;
|
||||
DateTime get updatedAt;
|
||||
}
|
||||
|
||||
class _StorableImp implements Storable {
|
||||
@override
|
||||
final String id;
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
@override
|
||||
final DateTime updatedAt;
|
||||
|
||||
const _StorableImp({
|
||||
required this.id,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
Storable newStorable({String? id, DateTime? createdAt, DateTime? updatedAt}) => _StorableImp(
|
||||
id: id ?? Constants.nilObjectRef,
|
||||
createdAt: createdAt ?? DateTime.now().toUtc(),
|
||||
updatedAt: updatedAt ?? DateTime.now().toUtc(),
|
||||
);
|
||||
144
frontend/pshared/lib/provider/account.dart
Normal file
144
frontend/pshared/lib/provider/account.dart
Normal file
@@ -0,0 +1,144 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
import 'package:pshared/api/errors/unauthorized.dart';
|
||||
import 'package:pshared/api/requests/signup.dart';
|
||||
import 'package:pshared/models/account/account.dart';
|
||||
import 'package:pshared/provider/exception.dart';
|
||||
import 'package:pshared/provider/resource.dart';
|
||||
import 'package:pshared/service/account.dart';
|
||||
|
||||
|
||||
class AccountProvider extends ChangeNotifier {
|
||||
// The resource now wraps our Account? state along with its loading/error state.
|
||||
Resource<Account?> _resource = Resource(data: null);
|
||||
Resource<Account?> get resource => _resource;
|
||||
|
||||
Account? get account => _resource.data;
|
||||
bool get isLoggedIn => account != null;
|
||||
bool get isLoading => _resource.isLoading;
|
||||
Object? get error => _resource.error;
|
||||
|
||||
// Private helper to update the resource and notify listeners.
|
||||
void _setResource(Resource<Account?> newResource) {
|
||||
_resource = newResource;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
||||
Future<Account?> login({
|
||||
required String email,
|
||||
required String password,
|
||||
required String locale,
|
||||
}) async {
|
||||
_setResource(_resource.copyWith(isLoading: true, error: null));
|
||||
try {
|
||||
final acc = await AccountService.login(email, password, locale);
|
||||
_setResource(Resource(data: acc, isLoading: false));
|
||||
return acc;
|
||||
} catch (e) {
|
||||
_setResource(_resource.copyWith(isLoading: false, error: toException(e)));
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Account?> restore() async {
|
||||
_setResource(_resource.copyWith(isLoading: true, error: null));
|
||||
try {
|
||||
final acc = await AccountService.restore();
|
||||
_setResource(Resource(data: acc, isLoading: false));
|
||||
return acc;
|
||||
} catch (e) {
|
||||
_setResource(_resource.copyWith(isLoading: false, error: toException(e)));
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> signup(
|
||||
String name,
|
||||
String login,
|
||||
String password,
|
||||
String locale,
|
||||
String organizationName,
|
||||
String timezone,
|
||||
) async {
|
||||
_setResource(_resource.copyWith(isLoading: true, error: null));
|
||||
try {
|
||||
await AccountService.signup(
|
||||
SignupRequest.build(
|
||||
name: name,
|
||||
login: login.trim().toLowerCase(),
|
||||
password: password,
|
||||
locale: locale,
|
||||
organizationName: organizationName,
|
||||
organizationTimeZone: timezone,
|
||||
),
|
||||
);
|
||||
// Signup might not automatically log in the user,
|
||||
// so we just mark the request as complete.
|
||||
_setResource(_resource.copyWith(isLoading: false));
|
||||
} catch (e) {
|
||||
_setResource(_resource.copyWith(isLoading: false, error: toException(e)));
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> logout() async {
|
||||
_setResource(_resource.copyWith(isLoading: true, error: null));
|
||||
try {
|
||||
await AccountService.logout();
|
||||
_setResource(Resource(data: null, isLoading: false));
|
||||
} catch (e) {
|
||||
_setResource(_resource.copyWith(isLoading: false, error: toException(e)));
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Account?> update({
|
||||
String? locale,
|
||||
String? avatarUrl,
|
||||
String? notificationFrequency,
|
||||
}) async {
|
||||
if (account == null) throw ErrorUnauthorized();
|
||||
_setResource(_resource.copyWith(isLoading: true, error: null));
|
||||
try {
|
||||
final updated = await AccountService.update(
|
||||
account!.copyWith(
|
||||
avatarUrl: () => avatarUrl ?? account!.avatarUrl,
|
||||
locale: locale ?? account!.locale,
|
||||
),
|
||||
);
|
||||
_setResource(Resource(data: updated, isLoading: false));
|
||||
return updated;
|
||||
} catch (e) {
|
||||
_setResource(_resource.copyWith(isLoading: false, error: toException(e)));
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> changePassword(String oldPassword, String newPassword) async {
|
||||
if (account == null) throw ErrorUnauthorized();
|
||||
_setResource(_resource.copyWith(isLoading: true, error: null));
|
||||
try {
|
||||
final updated = await AccountService.changePassword(oldPassword, newPassword);
|
||||
_setResource(Resource(data: updated, isLoading: false));
|
||||
} catch (e) {
|
||||
_setResource(_resource.copyWith(isLoading: false, error: toException(e)));
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Account?> uploadAvatar(XFile avatarFile) async {
|
||||
if (account == null) throw ErrorUnauthorized();
|
||||
_setResource(_resource.copyWith(isLoading: true, error: null));
|
||||
try {
|
||||
final avatarUrl = await AccountService.uploadAvatar(account!.id, avatarFile);
|
||||
// Reuse the update method to update the avatar URL.
|
||||
return update(avatarUrl: avatarUrl);
|
||||
} catch (e) {
|
||||
_setResource(_resource.copyWith(isLoading: false, error: toException(e)));
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
58
frontend/pshared/lib/provider/accounts/employees.dart
Normal file
58
frontend/pshared/lib/provider/accounts/employees.dart
Normal file
@@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:pshared/models/organization/employee.dart';
|
||||
import 'package:pshared/provider/organizations.dart';
|
||||
import 'package:pshared/provider/resource.dart';
|
||||
import 'package:pshared/service/accounts/employees.dart';
|
||||
|
||||
|
||||
class EmployeesProvider extends ChangeNotifier {
|
||||
|
||||
Resource<List<Employee>> _employees = Resource<List<Employee>>(data: []);
|
||||
List<Employee> get employees => _employees.data ?? [];
|
||||
bool get isLoading => _employees.isLoading;
|
||||
Object? get error => _employees.error;
|
||||
Employee? getEmployee(String? employeeRef) => employees.firstWhereOrNull((employee) => employee.id == employeeRef);
|
||||
|
||||
|
||||
bool Function(Employee)? _filterPredicate;
|
||||
|
||||
List<Employee> get filteredItems => _filterPredicate != null
|
||||
? employees.where(_filterPredicate!).toList()
|
||||
: employees;
|
||||
|
||||
void setFilterPredicate(bool Function(Employee)? predicate) {
|
||||
_filterPredicate = predicate;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void clearFilter() => setFilterPredicate(null);
|
||||
|
||||
void updateProviders(OrganizationsProvider organizations) {
|
||||
load(organizations.current.id);
|
||||
}
|
||||
|
||||
Future<List<Employee>> load(String organizationRef) async {
|
||||
_employees = _employees.copyWith(isLoading: true, error: null);
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
final fetchedEmployees = await EmployeesService.list(organizationRef);
|
||||
_employees = _employees.copyWith(
|
||||
data: fetchedEmployees,
|
||||
isLoading: false,
|
||||
error: null,
|
||||
);
|
||||
} catch (e) {
|
||||
_employees = _employees.copyWith(
|
||||
error: e is Exception ? e : Exception('Unknown error: ${e.toString()}'),
|
||||
isLoading: false,
|
||||
);
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
return employees;
|
||||
}
|
||||
}
|
||||
3
frontend/pshared/lib/provider/exception.dart
Normal file
3
frontend/pshared/lib/provider/exception.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
Exception toException(Object e) {
|
||||
return e is Exception ? e : Exception(e.toString());
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user