account changes

This commit is contained in:
Andreas Knuth 2024-06-03 09:35:42 -05:00
parent d488f90f48
commit 3d5b7e3f39
10 changed files with 615 additions and 64 deletions

View File

@ -0,0 +1,7 @@
DO $$ BEGIN
CREATE TYPE "customerType" AS ENUM('buyer', 'broker', 'professional');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
ALTER TABLE "users" ADD COLUMN "customerType" "customerType";

View File

@ -0,0 +1,518 @@
{
"id": "0bc02618-4414-4e90-8c44-808737611da7",
"prevId": "fc58c59b-ac5c-406e-8fdb-b05de40aed17",
"version": "5",
"dialect": "pg",
"tables": {
"businesses": {
"name": "businesses",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"title": {
"name": "title",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"city": {
"name": "city",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"state": {
"name": "state",
"type": "char(2)",
"primaryKey": false,
"notNull": false
},
"price": {
"name": "price",
"type": "double precision",
"primaryKey": false,
"notNull": false
},
"favoritesForUser": {
"name": "favoritesForUser",
"type": "varchar(30)[]",
"primaryKey": false,
"notNull": false
},
"draft": {
"name": "draft",
"type": "boolean",
"primaryKey": false,
"notNull": false
},
"listingsCategory": {
"name": "listingsCategory",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"realEstateIncluded": {
"name": "realEstateIncluded",
"type": "boolean",
"primaryKey": false,
"notNull": false
},
"leasedLocation": {
"name": "leasedLocation",
"type": "boolean",
"primaryKey": false,
"notNull": false
},
"franchiseResale": {
"name": "franchiseResale",
"type": "boolean",
"primaryKey": false,
"notNull": false
},
"salesRevenue": {
"name": "salesRevenue",
"type": "double precision",
"primaryKey": false,
"notNull": false
},
"cashFlow": {
"name": "cashFlow",
"type": "double precision",
"primaryKey": false,
"notNull": false
},
"supportAndTraining": {
"name": "supportAndTraining",
"type": "text",
"primaryKey": false,
"notNull": false
},
"employees": {
"name": "employees",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"established": {
"name": "established",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"internalListingNumber": {
"name": "internalListingNumber",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"reasonForSale": {
"name": "reasonForSale",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"brokerLicencing": {
"name": "brokerLicencing",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"internals": {
"name": "internals",
"type": "text",
"primaryKey": false,
"notNull": false
},
"imagePath": {
"name": "imagePath",
"type": "varchar(200)",
"primaryKey": false,
"notNull": false
},
"created": {
"name": "created",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated": {
"name": "updated",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"visits": {
"name": "visits",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"lastVisit": {
"name": "lastVisit",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"businesses_userId_users_id_fk": {
"name": "businesses_userId_users_id_fk",
"tableFrom": "businesses",
"tableTo": "users",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"commercials": {
"name": "commercials",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"serial_id": {
"name": "serial_id",
"type": "serial",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"title": {
"name": "title",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"city": {
"name": "city",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"state": {
"name": "state",
"type": "char(2)",
"primaryKey": false,
"notNull": false
},
"price": {
"name": "price",
"type": "double precision",
"primaryKey": false,
"notNull": false
},
"favoritesForUser": {
"name": "favoritesForUser",
"type": "varchar(30)[]",
"primaryKey": false,
"notNull": false
},
"listingsCategory": {
"name": "listingsCategory",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"hideImage": {
"name": "hideImage",
"type": "boolean",
"primaryKey": false,
"notNull": false
},
"draft": {
"name": "draft",
"type": "boolean",
"primaryKey": false,
"notNull": false
},
"zipCode": {
"name": "zipCode",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"county": {
"name": "county",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"website": {
"name": "website",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"phoneNumber": {
"name": "phoneNumber",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"imageOrder": {
"name": "imageOrder",
"type": "varchar(200)[]",
"primaryKey": false,
"notNull": false
},
"imagePath": {
"name": "imagePath",
"type": "varchar(200)",
"primaryKey": false,
"notNull": false
},
"created": {
"name": "created",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated": {
"name": "updated",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"visits": {
"name": "visits",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"lastVisit": {
"name": "lastVisit",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"commercials_userId_users_id_fk": {
"name": "commercials_userId_users_id_fk",
"tableFrom": "commercials",
"tableTo": "users",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"firstname": {
"name": "firstname",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"lastname": {
"name": "lastname",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"email": {
"name": "email",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"phoneNumber": {
"name": "phoneNumber",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"companyName": {
"name": "companyName",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"companyOverview": {
"name": "companyOverview",
"type": "text",
"primaryKey": false,
"notNull": false
},
"companyWebsite": {
"name": "companyWebsite",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"companyLocation": {
"name": "companyLocation",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"offeredServices": {
"name": "offeredServices",
"type": "text",
"primaryKey": false,
"notNull": false
},
"areasServed": {
"name": "areasServed",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"hasProfile": {
"name": "hasProfile",
"type": "boolean",
"primaryKey": false,
"notNull": false
},
"hasCompanyLogo": {
"name": "hasCompanyLogo",
"type": "boolean",
"primaryKey": false,
"notNull": false
},
"licensedIn": {
"name": "licensedIn",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"gender": {
"name": "gender",
"type": "gender",
"primaryKey": false,
"notNull": false
},
"customerType": {
"name": "customerType",
"type": "customerType",
"primaryKey": false,
"notNull": false
},
"created": {
"name": "created",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated": {
"name": "updated",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {
"customerType": {
"name": "customerType",
"values": {
"buyer": "buyer",
"broker": "broker",
"professional": "professional"
}
},
"gender": {
"name": "gender",
"values": {
"male": "male",
"female": "female"
}
}
},
"schemas": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@ -8,6 +8,13 @@
"when": 1716495198537,
"tag": "0000_burly_bruce_banner",
"breakpoints": true
},
{
"idx": 1,
"version": "5",
"when": 1717085220861,
"tag": "0001_wet_mephistopheles",
"breakpoints": true
}
]
}

View File

@ -3,6 +3,7 @@ import { AreasServed, LicensedIn } from 'src/models/db.model';
export const PG_CONNECTION = 'PG_CONNECTION';
export const genderEnum = pgEnum('gender', ['male', 'female']);
export const customerTypeEnum = pgEnum('customerType', ['buyer', 'broker', 'professional']);
export const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
@ -21,6 +22,7 @@ export const users = pgTable('users', {
hasCompanyLogo: boolean('hasCompanyLogo'),
licensedIn: jsonb('licensedIn').$type<LicensedIn[]>(),
gender: genderEnum('gender'),
customerType: customerTypeEnum('customerType'),
created: timestamp('created'),
updated: timestamp('updated'),
});

View File

@ -15,6 +15,7 @@ export interface User {
hasCompanyLogo?: boolean;
licensedIn?: LicensedIn[];
gender?: 'male' | 'female';
customerType?: 'buyer' | 'broker' | 'professional';
created?: Date;
updated?: Date;
}
@ -35,6 +36,7 @@ export interface UserData {
hasCompanyLogo?: boolean;
licensedIn?: string[];
gender?: 'male' | 'female';
customerType?: 'buyer' | 'broker' | 'professional';
created?: Date;
updated?: Date;
}

View File

@ -3,16 +3,16 @@ import { SelectOptionsService } from './select-options.service.js';
@Controller('select-options')
export class SelectOptionsController {
constructor(private selectOptionsService:SelectOptionsService){}
constructor(private selectOptionsService: SelectOptionsService) {}
@Get()
getSelectOption():any{
getSelectOption(): any {
return {
typesOfBusiness:this.selectOptionsService.typesOfBusiness,
prices:this.selectOptionsService.prices,
listingCategories:this.selectOptionsService.listingCategories,
categories:this.selectOptionsService.categories,
locations:this.selectOptionsService.locations,
typesOfCommercialProperty:this.selectOptionsService.typesOfCommercialProperty,
}
typesOfBusiness: this.selectOptionsService.typesOfBusiness,
prices: this.selectOptionsService.prices,
listingCategories: this.selectOptionsService.listingCategories,
customerTypes: this.selectOptionsService.customerTypes,
locations: this.selectOptionsService.locations,
typesOfCommercialProperty: this.selectOptionsService.typesOfCommercialProperty,
};
}
}

View File

@ -39,9 +39,14 @@ export class SelectOptionsService {
{ name: 'Business', value: 'business' },
{ name: 'Commercial Property', value: 'commercialProperty' },
];
public categories: Array<KeyValueStyle> = [
{ name: 'Broker', value: 'broker', icon: 'pi-image', bgColorClass: 'bg-green-100', textColorClass: 'text-green-600' },
{ name: 'Professional', value: 'professional', icon: 'pi-globe', bgColorClass: 'bg-yellow-100', textColorClass: 'text-yellow-600' },
public customerTypes: Array<KeyValue> = [
{ name: 'Buyer', value: 'buyer' },
{ name: 'Broker', value: 'broker' },
{ name: 'Professional', value: 'professional' },
];
public gender: Array<KeyValue> = [
{ name: 'Male', value: 'male' },
{ name: 'Female', value: 'female' },
];
public imageTypes: ImageType[] = [
{ name: 'propertyPicture', upload: 'uploadPropertyPicture', delete: 'propertyPicture' },

View File

@ -8,10 +8,16 @@
<div class="flex gap-5 flex-column-reverse md:flex-row">
<div class="flex-auto p-fluid">
@if (user){
<div class="mb-4">
<div class="grid">
<div class="mb-4 col-12 md:col-6">
<label for="state" class="block font-medium text-900 mb-2">E-mail (required)</label>
<input id="state" type="text" [disabled]="true" pInputText [(ngModel)]="user.email" />
<p class="font-italic text-sm line-height-1">You can only modify your email by contacting us at support&#64;bizmatch.net</p>
<p class="font-italic text-xs line-height-1">You can only modify your email by contacting us at support&#64;bizmatch.net</p>
</div>
<div class="mb-4 col-12 md:col-6">
<label for="customerType" class="block font-medium text-900 mb-2">Customer Type</label>
<p-dropdown id="customerType" [options]="selectOptions?.customerTypes" [(ngModel)]="user.customerType" optionLabel="name" optionValue="value" placeholder="State" [style]="{ width: '100%' }"></p-dropdown>
</div>
</div>
<div class="grid">
<div class="mb-4 col-12 md:col-6">
@ -23,6 +29,7 @@
<input id="lastname" type="text" pInputText [(ngModel)]="user.lastname" />
</div>
</div>
@if (isProfessional){
<div class="grid">
<div class="mb-4 col-12 md:col-6">
<label for="firstname" class="block font-medium text-900 mb-2">Company Name</label>
@ -33,6 +40,7 @@
<input id="lastname" type="text" pInputText [(ngModel)]="user.description" />
</div>
</div>
} @if (isProfessional){
<div class="grid">
<div class="mb-4 col-12 md:col-4">
<label for="phoneNumber" class="block font-medium text-900 mb-2">Your Phone Number</label>
@ -47,6 +55,14 @@
<p-autoComplete [(ngModel)]="user.companyLocation" [suggestions]="suggestions" (completeMethod)="search($event)"></p-autoComplete>
</div>
</div>
} @else {
<div class="grid">
<div class="mb-4 col-12 md:col-6">
<label for="phoneNumber" class="block font-medium text-900 mb-2">Your Phone Number</label>
<p-inputMask mask="(999) 999-9999" placeholder="(123) 456-7890" [(ngModel)]="user.phoneNumber"></p-inputMask>
</div>
</div>
} @if (isProfessional){
<div class="mb-4">
<label for="companyOverview" class="block font-medium text-900 mb-2">Company Overview</label>
<p-editor [(ngModel)]="user.companyOverview" [style]="{ height: '320px' }" [modules]="editorModules">
@ -59,7 +75,6 @@
<ng-template pTemplate="header"></ng-template>
</p-editor>
</div>
<div class="mb-4">
<label for="areasServed" class="block font-medium text-900 mb-2">Areas We Serve</label>
@for (areasServed of user.areasServed; track areasServed){
@ -118,11 +133,12 @@
<span class="text-xs">&nbsp;(Add more licenses or remove existing ones.)</span>
<!-- <button pButton pRipple label="Add Licence" class="w-auto" (click)="addLicence()"></button> -->
</div>
}
} }
<div>
<button pButton pRipple label="Update Profile" class="w-auto" (click)="updateProfile(user)"></button>
</div>
</div>
@if (isProfessional){
<div>
<div class="flex flex-column align-items-center flex-or mb-8">
<span class="font-medium text-900 mb-2">Company Logo</span>
@ -172,6 +188,7 @@
></p-fileUpload>
</div>
</div>
}
</div>
<div class="text-900 font-semibold text-lg mt-3">Membership Level</div>
<p-divider></p-divider>

View File

@ -75,7 +75,7 @@ export class AccountComponent {
try {
this.user = await this.userService.getByMail(email);
} catch (e) {
this.user = { email, firstname: keycloakUser.firstName, lastname: keycloakUser.lastName, areasServed: [], licensedIn: [], companyOverview: '', offeredServices: '' };
this.user = { email, firstname: keycloakUser.firstName, lastname: keycloakUser.lastName, areasServed: [], licensedIn: [], companyOverview: '', offeredServices: '', customerType: 'broker' };
this.user = await this.userService.save(this.user);
}
}
@ -121,6 +121,9 @@ export class AccountComponent {
removeArea() {
this.user.areasServed.splice(this.user.areasServed.length - 1, 1);
}
get isProfessional() {
return this.user.customerType === 'broker' || this.user.customerType === 'professional';
}
select(event: any, type: 'company' | 'profile') {
const imageUrl = URL.createObjectURL(event.files[0]);
this.type = type;

View File

@ -1,9 +1,8 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { InitEditableRow } from 'primeng/table';
import { Injectable } from '@angular/core';
import { lastValueFrom } from 'rxjs';
import { environment } from '../../environments/environment';
import { KeyValue, KeyValueStyle } from '../../../../bizmatch-server/src/models/main.model';
import { environment } from '../../environments/environment';
@Injectable({
providedIn: 'root',
@ -13,15 +12,14 @@ export class SelectOptionsService {
constructor(private http: HttpClient) {}
async init() {
const allSelectOptions = await lastValueFrom(
this.http.get<any>(`${this.apiBaseUrl}/bizmatch/select-options`)
);
const allSelectOptions = await lastValueFrom(this.http.get<any>(`${this.apiBaseUrl}/bizmatch/select-options`));
this.typesOfBusiness = allSelectOptions.typesOfBusiness;
this.prices = allSelectOptions.prices;
this.listingCategories = allSelectOptions.listingCategories;
this.categories = allSelectOptions.categories;
this.customerTypes = allSelectOptions.customerTypes;
this.states = allSelectOptions.locations;
this.typesOfCommercialProperty = allSelectOptions.typesOfCommercialProperty
this.gender = allSelectOptions.gender;
this.typesOfCommercialProperty = allSelectOptions.typesOfCommercialProperty;
}
public typesOfBusiness: Array<KeyValueStyle>;
@ -31,49 +29,41 @@ export class SelectOptionsService {
public listingCategories: Array<KeyValue>;
public categories: Array<KeyValueStyle>;
public customerTypes: Array<KeyValue>;
public gender: Array<KeyValue>;
public states: Array<any>;
getState(value:string):string{
return this.states.find(l=>l.value===value)?.name
getState(value: string): string {
return this.states.find(l => l.value === value)?.name;
}
getBusiness(value:number):string{
return this.typesOfBusiness.find(t=>t.value===String(value))?.name
getBusiness(value: number): string {
return this.typesOfBusiness.find(t => t.value === String(value))?.name;
}
getCommercialProperty(value:number):string{
return this.typesOfCommercialProperty.find(t=>t.value===String(value))?.name
getCommercialProperty(value: number): string {
return this.typesOfCommercialProperty.find(t => t.value === String(value))?.name;
}
getListingsCategory(value:string):string{
return this.listingCategories.find(l=>l.value===value)?.name
getListingsCategory(value: string): string {
return this.listingCategories.find(l => l.value === value)?.name;
}
getCategory(value:string):string{
return this.categories.find(c=>c.value===value)?.name
getCustomerType(value: string): string {
return this.customerTypes.find(c => c.value === value)?.name;
}
getIcon(value:string):string{
return this.categories.find(c=>c.value===value)?.icon
getGender(value: string): string {
return this.gender.find(c => c.value === value)?.name;
}
getTextColor(value:string):string{
return this.categories.find(c=>c.value===value)?.textColorClass
getIconType(value: string): string {
return this.typesOfBusiness.find(c => c.value === value)?.icon;
}
getBgColor(value:string):string{
return this.categories.find(c=>c.value===value)?.bgColorClass
getTextColorType(value: string): string {
return this.typesOfBusiness.find(c => c.value === value)?.textColorClass;
}
getIconAndTextColor(value:string):string{
const category = this.categories.find(c=>c.value===value)
return `${category?.icon} ${category?.textColorClass}`
getBgColorType(value: number): string {
return this.typesOfBusiness.find(c => c.value === String(value))?.bgColorClass;
}
getIconType(value:string):string{
return this.typesOfBusiness.find(c=>c.value===value)?.icon
}
getTextColorType(value:string):string{
return this.typesOfBusiness.find(c=>c.value===value)?.textColorClass
}
getBgColorType(value:number):string{
return this.typesOfBusiness.find(c=>c.value===String(value))?.bgColorClass
}
getIconAndTextColorType(value:number):string{
const category = this.typesOfBusiness.find(c=>c.value===String(value))
return `${category?.icon} ${category?.textColorClass}`
getIconAndTextColorType(value: number): string {
const category = this.typesOfBusiness.find(c => c.value === String(value));
return `${category?.icon} ${category?.textColorClass}`;
}
}