🕵️ More immoscout details (#258)

* 🕵️ More immoscout details

- Added more details to immoscout api - description is now populated with a lot of data from the expose using app API
- You can ignore certificates, if deploying locally and using the http notification adapter
- More details for the test call/example for easier testing + placeholder image + actual values + address (famous Erika Mustermans address see https://de.wikipedia.org/wiki/Mustermann)
- Grater timeout for geocode since the api is sometimes slow in germany
- uiElement, type boolean, now has a label as well

* 👀 Requested changes + some extra

Req:
- using logger
- using node-fetch

Extra:
- boolean input fields will trigger the validate check, because they are set undefined at first - setting them to false if they are undefined now
- added more data to the description (phone number and name of the agent)

*  Fixed import

* ️ Toggle immoscout detail fetching

* ️ Requested change
This commit is contained in:
Noah Elijah Till
2026-03-08 09:08:40 +01:00
committed by GitHub
parent ba0732e1f6
commit eb53b68d45
9 changed files with 235 additions and 32 deletions

View File

@@ -304,6 +304,20 @@ export const useFredyState = create(
throw Exception;
}
},
async setImmoscoutDetails(enabled) {
try {
await xhrPost('/api/user/settings/immoscout-details', { immoscout_details: enabled });
set((state) => ({
userSettings: {
...state.userSettings,
settings: { ...state.userSettings.settings, immoscout_details: enabled },
},
}));
} catch (Exception) {
console.error('Error while trying to update immoscout details setting. Error:', Exception);
throw Exception;
}
},
},
};

View File

@@ -27,10 +27,13 @@ const sortAdapter = (a, b) => {
const validate = (selectedAdapter) => {
const results = [];
for (let uiElement of Object.values(selectedAdapter.fields || [])) {
if (uiElement.value == null && !uiElement.optional) {
if (uiElement.value == null && !uiElement.optional && uiElement.type !== 'boolean') {
results.push('All fields are mandatory and must be set.');
continue;
}
if (uiElement.type === 'boolean' && typeof uiElement.value !== 'boolean') {
uiElement.value = false;
}
if (uiElement.type === 'number') {
const numberValue = parseFloat(uiElement.value);
if (isNaN(numberValue) || numberValue < 0) {
@@ -153,12 +156,15 @@ export default function NotificationAdapterMutator({
return (
<Form key={key}>
{uiElement.type === 'boolean' ? (
<Switch
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
<Switch
checked={uiElement.value || false}
onChange={(checked) => {
setValue(selectedAdapter, uiElement, key, checked);
}}
/>
{uiElement.label}
</div>
) : (
<Form.Input
style={{ width: '100%' }}

View File

@@ -4,8 +4,8 @@
*/
import { useEffect, useState, useMemo } from 'react';
import { Divider, Button, AutoComplete, Toast, Banner } from '@douyinfe/semi-ui-19';
import { IconSave, IconHome } from '@douyinfe/semi-icons';
import { Divider, Button, AutoComplete, Toast, Banner, Switch } from '@douyinfe/semi-ui-19';
import { IconSave, IconHome, IconSearch } from '@douyinfe/semi-icons';
import { useSelector, useActions, useIsLoading } from '../../services/state/store';
import { xhrGet } from '../../services/xhr';
import { SegmentPart } from '../../components/segment/SegmentPart';
@@ -14,6 +14,7 @@ import debounce from 'lodash/debounce';
const UserSettings = () => {
const actions = useActions();
const homeAddress = useSelector((state) => state.userSettings.settings.home_address);
const immoscoutDetails = useSelector((state) => state.userSettings.settings.immoscout_details);
const [address, setAddress] = useState(homeAddress?.address || '');
const [coords, setCoords] = useState(homeAddress?.coords || null);
const saving = useIsLoading(actions.userSettings.setHomeAddress);
@@ -84,6 +85,33 @@ const UserSettings = () => {
</div>
</SegmentPart>
<Divider />
<SegmentPart
name="ImmoScout Details"
Icon={IconSearch}
helpText="When enabled, Fredy will fetch additional details (description, attributes, agent info) for each listing from ImmoScout. This provides richer notifications but makes an extra API call per listing."
>
<Banner
type="warning"
description="Enabling this feature significantly increases the number of API requests to ImmoScout. This raises the likelihood of being detected and rate-limited or blocked. Use at your own risk."
closeIcon={null}
style={{ marginBottom: '12px', maxWidth: '600px' }}
/>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
<Switch
checked={!!immoscoutDetails}
onChange={async (checked) => {
try {
await actions.userSettings.setImmoscoutDetails(checked);
Toast.success('ImmoScout details setting updated.');
} catch {
Toast.error('Failed to update setting.');
}
}}
/>
<span>Fetch detailed ImmoScout listings</span>
</div>
</SegmentPart>
<Divider />
<div style={{ marginTop: '20px' }}>
<Button icon={<IconSave />} theme="solid" type="primary" onClick={handleSave} loading={saving}>
Save Settings