Skip to content
Snippets Groups Projects
Commit 894b44df authored by OZGCloud's avatar OZGCloud
Browse files

Merge pull request 'OZG-6129-zufi-searchbar' (#702) from OZG-6129-zufi-searchbar into master

parents e57a18b0 e3793354
No related branches found
No related tags found
No related merge requests found
Showing
with 333 additions and 1 deletion
import { type Meta, type StoryObj } from '@storybook/angular';
import { InstantSearchComponent } from './instant-search.component';
const meta: Meta<InstantSearchComponent> = {
title: 'Instant search/Instant search',
component: InstantSearchComponent,
excludeStories: /.*Data$/,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<InstantSearchComponent>;
export const Default: Story = {
args: {
label: '',
placeholder: 'zuständige Stelle suchen',
headerText: 'In der OZG-Cloud',
},
};
export const SearchResults: Story = {
args: {
label: '',
placeholder: 'zuständige Stelle suchen',
headerText: 'In der OZG-Cloud',
searchResults: [
{
text: 'Landeshauptstadt Kiel - Ordnungsamt, Gewerbe- und Schornsteinfegeraufsicht',
subText: 'Fabrikstraße 8-10, 24103 Kiel',
onClick: () => undefined,
},
{
text: 'Amt für Digitalisierung, Breitband und Vermessung Nürnberg Außenstelle Hersbruck',
subText: 'Rathausmarkt 7, Hersbruck',
onClick: () => undefined,
},
],
},
};
import { EMPTY_STRING } from '@alfa-client/tech-shared';
import { getElementFromFixtureByType, mock } from '@alfa-client/test-utils';
import { EventEmitter } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormControl } from '@angular/forms';
import { TextInputComponent } from '../../form/text-input/text-input.component';
import { SearchFieldComponent } from './search-field.component';
describe('SearchFieldComponent', () => {
let component: SearchFieldComponent;
let fixture: ComponentFixture<SearchFieldComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SearchFieldComponent],
}).compileComponents();
fixture = TestBed.createComponent(SearchFieldComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
describe('inputClicked', () => {
it('should emit event', () => {
component.inputClicked = <any>mock(EventEmitter);
const input = getElementFromFixtureByType(fixture, TextInputComponent);
input.inputElement.nativeElement.click();
expect(component.inputClicked.emit).toHaveBeenCalled();
});
});
describe('clearValue', () => {
it('should set empty value', () => {
component.control = new FormControl('test');
component.clearInput();
expect(component.control.value).toBe(EMPTY_STRING);
});
});
});
import { CommonModule } from '@angular/common';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { FormControl } from '@angular/forms';
import { EMPTY_STRING } from '../../../../../tech-shared/src';
import { TextInputComponent } from '../../form/text-input/text-input.component';
import { CloseIconComponent } from '../../icons/close-icon/close-icon.component';
import { SearchIconComponent } from '../../icons/search-icon/search-icon.component';
@Component({
selector: 'ods-search-field',
standalone: true,
imports: [CommonModule, TextInputComponent, SearchIconComponent, CloseIconComponent],
template: `<ods-text-input
[label]="label"
[fieldControl]="control"
[placeholder]="placeholder"
[withPrefix]="true"
[withSuffix]="true"
(clickEmitter)="inputClicked.emit()"
role="combobox"
>
<ods-search-icon prefix aria-hidden="true" aria-label="Suchfeld" />
<button suffix *ngIf="control.value" (click)="clearInput()" aria-label="Eingabe löschen">
<ods-close-icon class="fill-primary hover:fill-primary-hover" />
</button>
</ods-text-input>`,
})
export class SearchFieldComponent {
@Input() label: string = EMPTY_STRING;
@Input() placeholder: string = EMPTY_STRING;
@Input() control = new FormControl(EMPTY_STRING);
@Output() inputClicked: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();
clearInput() {
this.control.setValue(EMPTY_STRING);
}
}
import { type Meta, type StoryObj } from '@storybook/angular';
import { SearchFieldComponent } from './search-field.component';
const meta: Meta<SearchFieldComponent> = {
title: 'Instant search/Search field',
component: SearchFieldComponent,
excludeStories: /.*Data$/,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<SearchFieldComponent>;
export const Default: Story = {
args: {
label: '',
placeholder: 'search something...',
},
};
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SearchResultHeaderComponent } from './search-result-header.component';
describe('SearchResultHeaderComponent', () => {
let component: SearchResultHeaderComponent;
let fixture: ComponentFixture<SearchResultHeaderComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SearchResultHeaderComponent],
}).compileComponents();
fixture = TestBed.createComponent(SearchResultHeaderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { CommonModule } from '@angular/common';
import { Component, Input } from '@angular/core';
@Component({
selector: 'ods-search-result-header',
standalone: true,
imports: [CommonModule],
template: `
<h3 class="mx-6 my-3 w-fit border-b-2 border-primary py-1 text-sm font-semibold text-text">
{{ text }} ({{ count }})
</h3>
`,
})
export class SearchResultHeaderComponent {
@Input({ required: true }) text!: string;
@Input() count: number = 0;
}
import { getElementFromFixture, mock } from '@alfa-client/test-utils';
import { EventEmitter } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
import { SearchResultItemComponent } from './search-result-item.component';
describe('SearchResultItemComponent', () => {
let component: SearchResultItemComponent;
let fixture: ComponentFixture<SearchResultItemComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SearchResultItemComponent],
}).compileComponents();
fixture = TestBed.createComponent(SearchResultItemComponent);
component = fixture.componentInstance;
component.title = 'Test';
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
describe('itemClicked', () => {
it('should emit event', () => {
component.itemClicked = <any>mock(EventEmitter);
const button = getElementFromFixture(fixture, getDataTestIdOf('item-button'));
button.click();
expect(component.itemClicked.emit).toHaveBeenCalled();
});
});
describe('setFocus', () => {
it('should focus native element', () => {
component.buttonRef.nativeElement.focus = jest.fn();
component.setFocus();
expect(component.buttonRef.nativeElement.focus).toHaveBeenCalled();
});
});
});
import { CommonModule } from '@angular/common';
import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';
@Component({
selector: 'ods-search-result-item',
standalone: true,
imports: [CommonModule],
template: `<button
*ngIf="title"
[ngClass]="[
'flex w-full justify-between border-2 border-transparent px-6 py-3',
'hover:border-focus focus:border-focus focus:outline-none',
]"
role="listitem"
tabindex="-1"
(click)="itemClicked.emit()"
data-test-id="item-button"
#button
>
<div class="flex flex-col items-start justify-between text-text">
<p class="text-base font-medium">{{ title }}</p>
<p class="text-sm">{{ description }}</p>
</div>
<ng-content select="[action-button]" />
</button>`,
})
export class SearchResultItemComponent {
@Input({ required: true }) title!: string;
@Input() description: string = '';
@Output() public itemClicked: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();
@ViewChild('button') buttonRef: ElementRef;
public setFocus() {
this.buttonRef.nativeElement.focus();
}
}
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SearchResultLayerComponent } from './search-result-layer.component';
describe('SearchResultLayerComponent', () => {
let component: SearchResultLayerComponent;
let fixture: ComponentFixture<SearchResultLayerComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SearchResultLayerComponent],
}).compileComponents();
fixture = TestBed.createComponent(SearchResultLayerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
@Component({
selector: 'ods-search-result-layer',
standalone: true,
imports: [CommonModule],
template: `<div class="rounded-lg border border-primary-600/50 bg-background-50 shadow-lg">
<ng-content select="[header]" />
<ul role="list">
<ng-content />
</ul>
</div>`,
})
export class SearchResultLayerComponent {}
import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
import { SearchResultHeaderComponent } from '../search-result-header/search-result-header.component';
import { SearchResultItemComponent } from '../search-result-item/search-result-item.component';
import { SearchResultLayerComponent } from './search-result-layer.component';
const meta: Meta<SearchResultLayerComponent> = {
title: 'Instant search/Search result layer',
component: SearchResultLayerComponent,
excludeStories: /.*Data$/,
tags: ['autodocs'],
decorators: [
moduleMetadata({
imports: [SearchResultItemComponent, SearchResultHeaderComponent],
}),
],
};
export default meta;
type Story = StoryObj<SearchResultLayerComponent>;
export const Default: Story = {
args: {},
render: () => ({
template: `<ods-search-result-layer>
<ods-search-result-header text="In der OZG-Cloud" [count]="2" header />
<ods-search-result-item text="Amt Rantznau - Ordnungsamt" subText="Rathausmarkt 7, Kronshagen" />
<ods-search-result-item text="Amt Burg-St. Michaelisdonn - Der Amtsvorsteher" subText="Holzmarkt 7, 25712 Rantznau" />
</ods-search-result-layer>`,
}),
};
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
value="false" value="false"
data-test-id="button-abgelehnt" data-test-id="button-abgelehnt"
variant="bescheid_abgelehnt" variant="bescheid_abgelehnt"
><ods-close-icon size="medium" class="fill-abgelehnt"></ods-close-icon> ><ods-close-icon size="large" class="fill-abgelehnt"></ods-close-icon>
</ods-radio-button-card> </ods-radio-button-card>
</div> </div>
<div class="flex w-full"> <div class="flex w-full">
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment