Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spend options #359

Open
wants to merge 18 commits into
base: dfg/sum24-involvemint
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion angular.json
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@
},
"apps/involvemint/src/manifest.webmanifest"
],
"styles": ["apps/involvemint/src/styles.scss"],
"styles": ["./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", "apps/involvemint/src/styles.scss"],
"scripts": [],
"serviceWorker": true,
"ngswConfigPath": "apps/involvemint/ngsw-config.json",
7 changes: 5 additions & 2 deletions apps/involvemint/src/index.html
Original file line number Diff line number Diff line change
@@ -14,8 +14,11 @@
<meta http-equiv="Expires" content="0" />
<link rel="manifest" href="manifest.webmanifest" />
<meta name="theme-color" content="#1976d2" />
</head>
<body>
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body class="mat-typography">
<involvemint-root></involvemint-root>
<noscript>Please enable JavaScript to continue using this application.</noscript>
</body>
6 changes: 5 additions & 1 deletion apps/involvemint/src/styles.scss
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
@import '@involvemint/scss/_index.scss';
@import '@involvemint/scss/_index.scss';


html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
6 changes: 5 additions & 1 deletion apps/migrate/src/app/app.service.ts
Original file line number Diff line number Diff line change
@@ -210,7 +210,10 @@ export class AppService {
requests: [],
sendingTransactions: [],
sendingVouchers: [],
view: null,
view: null,
tags: ep.tags,
spendingOptions: ep.spendingOptions

};
})
.filter((u) => !!u)
@@ -777,6 +780,7 @@ export class AppService {
address: address,
listingStatus: e.listed ? 'public' : 'private',
price: e.price,

};
}).filter((u) => !!u)
)
34 changes: 34 additions & 0 deletions libs/client/ep/shell/src/lib/storefront/storefront.component.html
Original file line number Diff line number Diff line change
@@ -48,6 +48,40 @@
</im-error>
</im-item>


<im-item [touched]="true" label="Add Tags">
<ion-item>
<ion-select (ionChange)="onTagSelected($event)" placeholder="Select a tag">
<ion-select-option *ngFor="let tag of availableTags" [value]="tag">{{ tag }}</ion-select-option>
</ion-select>
</ion-item>
</im-item>

<div style="margin-bottom: 20px;" class="tags" *ngIf="storeFrontForm.get('tags')?.value.length > 0">
<div class="tag" *ngFor="let tag of storeFrontForm.get('tags')?.value; let i = index">
<span >{{ tag }}</span>
<ion-icon name="close-circle" (click)="removeTag(i)"></ion-icon>
</div>
</div>

<im-item [touched]="true" label="Select Spending Options">
<ion-item>
<ion-select formControlName="spendingOptions" placeholder="Select an Option">
<ion-select-option value="In-Person">In-Person</ion-select-option>
<ion-select-option value="Virtual">Virtual</ion-select-option>
<ion-select-option value="Both">Both</ion-select-option>
</ion-select>
</ion-item>
</im-item>









<div>
<div class="im-primary-text">Storefront Images:</div>
<div class="images-cont">
16 changes: 16 additions & 0 deletions libs/client/ep/shell/src/lib/storefront/storefront.component.scss
Original file line number Diff line number Diff line change
@@ -14,4 +14,20 @@
padding: 0.5em;
color: black;
}


}
.tags {
display:flex ;
gap: 10px ;
}
.tag {
background-color: var(--ion-color-primary) ;
padding: 4px 8px ;
border-radius: 8px ;
color:white ;
display:flex ;
align-items: center;
gap: 2px ;

}
49 changes: 46 additions & 3 deletions libs/client/ep/shell/src/lib/storefront/storefront.component.ts
Original file line number Diff line number Diff line change
@@ -19,7 +19,9 @@ import {
} from '@involvemint/shared/domain';
import { tapOnce, UnArray } from '@involvemint/shared/util';
import { FormControl, FormGroup } from '@ngneat/reactive-forms';
import { filter, skip, switchMap, tap, take } from 'rxjs/operators';
import { filter, skip, switchMap, tap ,take } from 'rxjs/operators';
import { FormBuilder} from '@angular/forms';


type Profile = NonNullable<UnArray<UserStoreModel['exchangeAdmins']>['exchangePartner']>;

@@ -37,13 +39,19 @@ interface State {
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class StorefrontComponent extends StatefulComponent<State> implements OnInit {

@ViewChild('tabs') tabs!: ImTabsComponent;
availableTags: string[] = ['Essentials', 'Arts & Entertainment', 'Professional Services', 'Trades', 'Rentals', 'Farming/Land', 'Food & Food Services', 'Health & Wellness', 'Transportation', 'Home Services', 'Youth', 'Seniors', 'Education/Training', 'Retail', 'Media & Print', 'Free'];



readonly storeFrontForm = new FormGroup({
listStoreFront: new FormControl<StorefrontListingStatus>(defaultProjectListingStatus, (e) =>
Validators.required(e)
),
description: new FormControl('', [Validators.maxLength(ImConfig.maxDescriptionLength)]),
tags: new FormControl<string[]>([]),
spendingOptions: new FormControl('')
});

readonly listingOptions: StorefrontListingStatus[] = ['public', 'private', 'unlisted'];
@@ -55,12 +63,14 @@ export class StorefrontComponent extends StatefulComponent<State> implements OnI
private readonly status: StatusService,
private readonly imagesViewer: ImImagesViewerModalService,
private readonly route: RouteService,
private readonly activatedRoute: ActivatedRoute
private readonly activatedRoute: ActivatedRoute,
) {
super({ activeTabIndex: 0, profile: null, deepLink: null, savingState: 'saved' });

}

ngOnInit(): void {

this.activatedRoute.queryParams.pipe().subscribe(async ({ activeTab }) => {
if (!activeTab) {
return;
@@ -91,9 +101,13 @@ export class StorefrontComponent extends StatefulComponent<State> implements OnI
if (!exchangePartner) {
return;
}
console.log(exchangePartner)
this.storeFrontForm.patchValue({
listStoreFront: exchangePartner.listStoreFront,
description: exchangePartner.description,
tags: exchangePartner.tags,
spendingOptions: exchangePartner.spendingOptions

});
}),
tap((exchangePartner) => {
@@ -107,10 +121,16 @@ export class StorefrontComponent extends StatefulComponent<State> implements OnI
switchMap(() => this.storeFrontForm.valueChanges),
skip(1),
tap((form) => {
console.log(this.storeFrontForm.get('tags')?.value)
console.log(this.storeFrontForm.get('description')?.value)
console.log(form.tags)
console.log(form.description)
this.updateState({ savingState: 'saving' });
this.user.epProfile.dispatchers.editEpProfile({
listStoreFront: form.listStoreFront,
description: form.description,
tags: form.tags,
spendingOptions: form.spendingOptions
});
}),

@@ -150,6 +170,7 @@ export class StorefrontComponent extends StatefulComponent<State> implements OnI
});
}


async viewImages(paths: string[], index: number): Promise<void> {
await this.imagesViewer.open({ imagesFilePaths: paths, slideIndex: index });
}
@@ -158,7 +179,7 @@ export class StorefrontComponent extends StatefulComponent<State> implements OnI
let files: File[] | undefined;
try {
files = parseMultipleFiles(event);
} catch (error) {
} catch (error:any) {
this.status.presentAlert({ title: 'Error', description: error.message });
}

@@ -167,10 +188,32 @@ export class StorefrontComponent extends StatefulComponent<State> implements OnI
this.user.epProfile.dispatchers.uploadEpImages(files);
}



deleteImage(imagesFilePathsIndex: number): void {
this.user.epProfile.dispatchers.deleteEpImage(imagesFilePathsIndex);
}

addTag(tag: string) {
console.log("we are hereeeeee")
const currentTags = this.storeFrontForm.get('tags')?.value || [];
if (tag && !currentTags.includes(tag)) {
this.storeFrontForm.get('tags')?.patchValue([...currentTags, tag]);
console.log('Updated Tags:', this.storeFrontForm.get('tags')?.value);
}
}

onTagSelected(event: any) {
const selectedTag = event.detail.value;
this.addTag(selectedTag);
}

removeTag(index: number): void {
const currentTags = [...this.storeFrontForm.get('tags')?.value]; // Make a copy of the array
currentTags.splice(index, 1);
this.storeFrontForm.get('tags')?.patchValue([...currentTags]);
}

makeCoverPhoto(
ep: UnArray<UserStoreModel['exchangeAdmins']>['exchangePartner'],
imagesFilePathsIndex: number
2 changes: 2 additions & 0 deletions libs/client/ep/shell/src/lib/storefront/storefront.module.ts
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ import { ImRoutes } from '@involvemint/shared/domain';
import { IonicModule } from '@ionic/angular';
import { AutosizeModule } from 'ngx-autosize';
import { StorefrontComponent } from './storefront.component';
import {FormsModule} from '@angular/forms';

@NgModule({
imports: [
@@ -29,6 +30,7 @@ import { StorefrontComponent } from './storefront.component';
ImStorageUrlPipeModule,
OffersModule,
RequestsModule,
FormsModule,
RouterModule.forChild([
{
path: '',
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ export interface ExchangeAdminsWithBaDownloaded extends UnArray<UserStoreModel['
baDownloaded: boolean;
}


export interface UserSessionState extends UserStoreModel {
activeProfileId: string | null;
navTabs: boolean;
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<super-tab imRemoveWrapper>
<super-tab imRemoveWrapper [ngClass]="{'disabled': disabled}">
<ng-content></ng-content>
</super-tab>
Original file line number Diff line number Diff line change
@@ -8,4 +8,5 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
})
export class ImTabComponent {
@Input() label = '';
@Input() disabled = false;
}
8 changes: 6 additions & 2 deletions libs/client/shared/ui/src/lib/im-tabs/im-tabs.component.html
Original file line number Diff line number Diff line change
@@ -5,8 +5,12 @@
[activeTabIndex]="activeTabIndex"
>
<super-tabs-toolbar imSuperTabsToolbarTheme [slot]="slot" [scrollable]="true" [scrollablePadding]="false">
<super-tab-button *ngFor="let label of labels$ | async">
<ion-label>{{ label }}</ion-label>
<super-tab-button *ngFor="let tab of tabs.toArray(); let i = index"
[ngClass]="{ 'disabled': tabs.toArray()[i].disabled }"
[class.disabled]="tab.disabled"
[disabled]="tab.disabled"
(click)="tab.disabled ? null : selectTab(i)">
<ion-label>{{ tab.label }}</ion-label>
</super-tab-button>
</super-tabs-toolbar>
<super-tabs-container
14 changes: 13 additions & 1 deletion libs/client/shared/ui/src/lib/im-tabs/im-tabs.component.scss
Original file line number Diff line number Diff line change
@@ -13,17 +13,28 @@ super-tab-button {
flex-grow: 1;
max-width: 100%;
padding: 0;

ion-label {
text-transform: none;
}
}

super-tab-button.disabled {
color: #ccc;
pointer-events: none;
opacity: 0.3;
background-color: #f5f5f5;
}



super-tab-button:nth-child(even) {
box-shadow: 0px 0px 0px 1px var(--im-border-color);
z-index: 1;
}



super-tabs-toolbar {
background: var(--im-menu-item);
height: 40px;
@@ -51,3 +62,4 @@ super-tabs-container,
border-top: 0;
border-bottom: 1px solid var(--im-border-color);
}

22 changes: 20 additions & 2 deletions libs/client/shared/ui/src/lib/im-tabs/im-tabs.component.ts
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ export class ImTabsComponent extends RxJSBaseClass implements AfterContentInit {
@Input() activeTabIndex = 0;
@Input() padding = '0px 0px 0px 0px';
@Input() swipeEnabled = true;


@Output() tabChange = new EventEmitter<number>();

@@ -40,7 +41,21 @@ export class ImTabsComponent extends RxJSBaseClass implements AfterContentInit {
}

tabChangeEvent(event: Event) {
this.tabChange.emit((event as CustomEvent).detail.index);
const newIndex = (event as CustomEvent).detail.index;
const tabArray = this.tabs.toArray();
if (!tabArray[newIndex]?.disabled) {
this.tabChange.emit(newIndex);
this.activeTabIndex = newIndex;
} else {
this.superTabs.selectTab(this.activeTabIndex);
}
}

selectTab(index: number) {
if (!this.tabs.toArray()[index]?.disabled) {
this.superTabs.selectTab(index);
this.activeTabIndex = index;
}
}

ngAfterContentInit() {
@@ -53,6 +68,9 @@ export class ImTabsComponent extends RxJSBaseClass implements AfterContentInit {
}

setIndex(index: number) {
this.superTabs.selectTab(index);
if (!this.tabs.toArray()[index]?.disabled) {
this.superTabs.selectTab(index);
}
}

}
Original file line number Diff line number Diff line change
@@ -29,8 +29,13 @@
</ion-header>

<ion-content>
<im-tabs *ngIf="state.exchangePartner as ep" #tabs [swipeEnabled]="false">
<im-tab label="Storefront">
<im-tabs *ngIf="state.exchangePartner as ep" #tabs [swipeEnabled]="false"
[activeTabIndex]="state.exchangePartner.spendingOptions === 'Virtual' ? 1 : 0">
<im-tab label="Storefront"

[disabled]="ep.spendingOptions === 'Virtual'"

>
<div class="im-cont">
<div class="im-primary-text title">{{ ep!.name }}</div>
<im-image-slides
@@ -72,7 +77,8 @@
</div>
</div>
</im-tab>
<im-tab label="Offers">
<im-tab label="Offers" [disabled]="ep.spendingOptions === 'In-Person'"
>
<div class="im-cont">
<div class="im-primary-text" style="text-align: center">Items For Sale</div>
<div style="text-align: center" *ngIf="ep.offers.length === 0">No offers listed.</div>
Loading