Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a30e6fb
Moving files
hejny Nov 4, 2023
ad69490
Using freewhois (RDAP) to check domains
hejny Nov 4, 2023
a754225
Lookup domain in playground
hejny Nov 5, 2023
685fd03
Domain lookup
hejny Nov 5, 2023
6f7fbf2
Timeout in domain info
hejny Nov 5, 2023
fbb06ae
Remove check-whois endpoint
hejny Nov 5, 2023
1a2360d
<DomainsModal/>
hejny Nov 5, 2023
f9379bd
Reinstall dependencies
hejny Nov 5, 2023
81bf67f
lookupDomain working
hejny Nov 5, 2023
4833330
Domain checker modal
hejny Nov 5, 2023
a5259ad
Split <DomainStatusText/> and <DomainStatusChecker>
hejny Nov 5, 2023
d509da8
<DomainsModal/> uses <DomainStatusText/>
hejny Nov 5, 2023
9e77a72
Fixing domains modal
hejny Nov 5, 2023
cd41cc3
Miltiple domain checking components
hejny Nov 6, 2023
9bad848
Update lookupDomain.ts
hejny Nov 6, 2023
dafef8c
Update lookupDomain.ts
hejny Nov 6, 2023
24f0baa
Update DomainStatusChecker.tsx
hejny Nov 6, 2023
59f67e1
Normalize domain names before checking
hejny Nov 6, 2023
3509c5b
Update dependencies
hejny Nov 6, 2023
3368f88
Better checking of domains
hejny Nov 6, 2023
adc1b3d
Rename AttemptCount -> TryCount
hejny Nov 6, 2023
bfb5798
Domain checkedAt
hejny Nov 6, 2023
c90819d
Layout
hejny Nov 6, 2023
9adc08c
RDAP lookup timeout
hejny Nov 6, 2023
4423e89
Retry after longer spread
hejny Nov 6, 2023
b2afec5
Retry after longer spread
hejny Nov 6, 2023
2e0cfb5
Domains checkedAt in brackets
hejny Nov 6, 2023
65b92c7
Important TODOs
hejny Nov 6, 2023
b85573c
Fix types
hejny Nov 6, 2023
71c2934
Merge branch 'main' into feature/domain-wizzard
hejny Nov 30, 2023
c77bf9d
Merge branch 'main' into feature/domain-wizzard
hejny Dec 1, 2023
809deb9
Merge branch 'main' into feature/domain-wizzard
hejny Dec 6, 2023
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
1 change: 1 addition & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const jestConfig = {
coverageDirectory: './coverage/',
collectCoverage: true,
testEnvironment: 'jsdom',
setupFiles: ['./jest.setup.ts'],
};

export default jestConfig;
1 change: 1 addition & 0 deletions jest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import 'whatwg-fetch';
487 changes: 450 additions & 37 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@
"typescript": "4.9.4",
"uuid": "9.0.0",
"waitasecond": "1.11.1",
"whoiser": "1.17.1",
"xmldom-qsa": "1.1.3",
"xyzt": "5.4.0",
"yaml": "2.2.2"
Expand Down
20 changes: 3 additions & 17 deletions scripts/playground/playground.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import * as dotenv from 'dotenv';
dotenv.config({ path: '.env' });

import chalk from 'chalk';
import OpenAI from 'openai';
import { join } from 'path';
import { OPENAI_API_KEY } from '../../config';

Expand All @@ -30,22 +29,9 @@ async function playground() {
// Do here stuff you want to test
//========================================>

const openai = new OpenAI({
apiKey: OPENAI_API_KEY,
});

const generatedImage = await openai.images.generate({
prompt: 'A dog',
model: 'dall-e-2',
n: 0,
size: '256x256',
// size: '1792x1024',
// quality: 'standard',
// style: 'natural',
user: 'playground',
});

console.log(generatedImage);
console.log('--------------------');
console.log(JSON.stringify(await lookupDomain(`towns.cz`), null, 4));
console.log('--------------------');
//========================================/

console.info(`[ Done 🧸 Playground ]`);
Expand Down
91 changes: 91 additions & 0 deletions src/components/Domains/DomainStatusChecker/DomainStatusChecker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { useEffect, useState } from 'react';
import { forTime } from 'waitasecond';
import { checkDomain } from '../../../utils/domains/checkDomain';
import { DomainStatus } from '../../../utils/domains/DomainStatus';

import { justNoActionWith } from '../../../utils/justNoActionWith';
import type { DomainStatusTextProps } from '../DomainStatusText/DomainStatusText';
import { DomainStatusText } from '../DomainStatusText/DomainStatusText';
import styles from '../DomainStatusText/DomainStatusText.module.css';

interface DomainStatusCheckerProps extends Omit<DomainStatusTextProps, 'domainStatus' | 'tryCount' | 'checkedAt'> {
/**
* Is checking immediately after the component is mounted OR after some debounce time
*/
isDebounced: boolean;

/**
* Is auto refreshed after some time when the domain is UNKNOWN, LIMIT or TIMEOUT
*/
isRetried: boolean;
}

/**
* Renderrs an info about a domain
*
* Note: It internally fetches and displays the whois
*/
export function DomainStatusChecker(props: DomainStatusCheckerProps) {
const { domain, isActionButtonShown, isShownDetailedFail, isDebounced, isRetried, className } = props;

const [domainStatus, setDomainStatus] = useState<keyof typeof DomainStatus | 'PENDING'>('PENDING');
const [checkedAt, setCheckedAt] = useState<Date | null>(null);
const [tryCount, setTryCount] = useState(1);
const domainStatusPromise = useEffect(() => {
let isDestroyed = false;

(async () => {
if (isDebounced) {
await forTime(200 /* <- TODO: !! DEBOUNCE_TIME_MS to config */);
}
if (isDestroyed) {
return;
}
justNoActionWith(tryCount);
const domainStatus = await checkDomain(domain);

if (['LIMIT', 'TIMEOUT', 'UNKNOWN'].includes(domainStatus)) {
await forTime(5000 + Math.random() * 10000 /* <- TODO: !! RETRY_TIME_MS to config */);
setTryCount(tryCount + 1);
}

setCheckedAt(new Date());
setDomainStatus(domainStatus);
})();

return () => {
isDestroyed = true;
};
}, [domain, isDebounced, isRetried, tryCount]);

let domainStatusShown = domainStatus;

if (
['LIMIT', 'TIMEOUT', 'NOT_SUPPORTED'].includes(domainStatusShown as keyof typeof DomainStatus | 'PENDING') &&
!isShownDetailedFail
) {
domainStatusShown = 'UNKNOWN';
}

return (
<>
<DomainStatusText
{...{ domain, isActionButtonShown, isShownDetailedFail, className, tryCount, checkedAt }}
domainStatus={domainStatusShown}
/>
{isActionButtonShown && ['UNKNOWN', 'LIMIT'].includes(domainStatusShown as any) && (
<button
style={{ cursor: 'pointer' }}
className={styles.action}
onClick={() => setTryCount(tryCount + 1)}
>
Refresh
</button>
)}
</>
);
}

/**
* TODO: !! Probbably debounce the whois lookup
*/
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
color: #888888;
}

.DomainStatusText .timeoput {
color: #888888;
}
.DomainStatusText .limit {
color: #888888;
}
.DomainStatusText span b {
color: inherit;
}
Expand Down
79 changes: 49 additions & 30 deletions src/components/Domains/DomainStatusText/DomainStatusText.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,44 @@
import moment from 'moment';
import Link from 'next/link';
import { useMemo } from 'react';
import { classNames } from '../../../utils/classNames';
import { checkDomain } from '../../../utils/domains/checkDomain';
import { usePromise } from '../../../utils/hooks/usePromise';
import { string_css_class, string_domain } from '../../../utils/typeAliases';
import type { DomainStatus } from '../../../utils/domains/DomainStatus';
import { getDomainTdl } from '../../../utils/domains/getDomainTdl';
import type { string_css_class, string_domain } from '../../../utils/typeAliases';
import styles from './DomainStatusText.module.css';

interface DomainStatusTextProps {
export interface DomainStatusTextProps {
/**
* The domain to check
* The domain which is checked
*
* Note: The domain will be normalized - trimmed and lowercased
* Note: The domain should be normalized - trimmed and lowercased
*/
domain: string_domain;

/**
* Status of the domain
*/
domainStatus: keyof typeof DomainStatus | 'PENDING';

/**
* How much attempts to check were done?
*/
tryCount: number;

/**
* When was the domain checked?
*/
checkedAt: Date | null;

/**
* Is button to open page shown?
*/
isActionButtonShown?: boolean;

/**
* Is shown that the domain exceeded limit for whois lookups?
* Is shown that the domain exceeded limit, timeout or not supported tdl for whois lookups?
* If no or not set, it will be shown as UNKNOWN
*/
isShownExceededLimit?: boolean;
isShownDetailedFail?: boolean;

/**
* Optional CSS class name which will be added to root element
Expand All @@ -37,15 +52,20 @@ interface DomainStatusTextProps {
* Note: It internally fetches and displays the whois
*/
export function DomainStatusText(props: DomainStatusTextProps) {
const { domain, isActionButtonShown, isShownExceededLimit, className } = props;
const { domain, isActionButtonShown, isShownDetailedFail, tryCount, checkedAt, className } = props;
let { domainStatus } = props;

const domainStatusPromise = useMemo(() => /* not await */ checkDomain(domain), [domain]);
let { value: domainStatus } = usePromise(domainStatusPromise, [domain]);

if (domainStatus === 'LIMIT' && !isShownExceededLimit) {
if (['LIMIT', 'TIMEOUT', 'NOT_SUPPORTED'].includes(domainStatus as any) && !isShownDetailedFail) {
domainStatus = 'UNKNOWN';
}

const tryCountMessage = tryCount > 1 ? <i>(Tried {tryCount}x)</i> : <></>;
const checkedAtMessage = checkedAt ? (
<i>({moment(checkedAt).calendar(/* <- TODO: !! Use current locale */)})</i>
) : (
<></>
);

return (
<div
// onClick={() => console.info(whois)}
Expand All @@ -55,12 +75,12 @@ export function DomainStatusText(props: DomainStatusTextProps) {
{
PENDING: (
<span className={styles.pending}>
<b>{domain}</b>: Getting whois info...
<b>{domain}</b>: Getting info about domain ⏣ {/* <- TODO: Circle between ⌬ and ⏣ */}
</span>
),
AVAILABLE: (
<span className={styles.available}>
<b>{domain}</b> is available for registration
<b>{domain}</b> is available for registration {checkedAtMessage}
</span>
),
REGISTERED: (
Expand All @@ -70,24 +90,27 @@ export function DomainStatusText(props: DomainStatusTextProps) {
),
LIMIT: (
<span className={styles.unknown}>
<b>{domain}</b> exceeded limit for whois lookups
<b>{domain}</b> exceeded limit for whois lookups {tryCountMessage}
</span>
),
TIMEOUT: (
<span className={styles.timeout}>
<b>{domain}</b> timeouted while getting whois info {tryCountMessage}
</span>
),
// TODO: TIMEOUT: <span className={styles.unknown}>Timeout in whois lookup</span>,
UNKNOWN: (
<span className={styles.unknown}>
<b>{domain}</b> status is unknown
<b>{domain}</b> status is unknown {tryCountMessage}
</span>
),
TDL_NOT_SUPPORTED: (
<span className={styles.unknown}>
<b>{domain}</b> unfortunately we can not check .{getDomainTdl(domain)} domains
</span>
),
}[domainStatus || 'PENDING']
}[domainStatus]
}

{/* TODO: [🧠] How to refresh the domain information?
<button style={{ cursor: 'pointer' }} className={styles.action} onClick={() => setNonce(nonce + 1)}>
Refresh
</button>
*/}

{/* TODO: [🧠] How/where to offer domain registration?
{domainStatus === 'AVAILABLE' && (
<Link
Expand All @@ -113,7 +136,3 @@ export function DomainStatusText(props: DomainStatusTextProps) {
</div>
);
}

/**
* TODO: !! Probbably debounce the whois lookup
*/

This file was deleted.

28 changes: 0 additions & 28 deletions src/components/Domains/DomainsStatusList/DomainsStatusList.tsx

This file was deleted.

11 changes: 9 additions & 2 deletions src/components/Domains/SimpleDomainChecker.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from 'react';
import { string_hostname } from '../../utils/typeAliases';
import { DomainStatusText } from './DomainStatusText/DomainStatusText';
import { DomainStatusChecker } from './DomainStatusChecker/DomainStatusChecker';

/**
* Renders a simple domain checker with a single input and single output
Expand All @@ -15,7 +15,14 @@ export function SimpleDomainChecker() {
onChange={(event) => setDomain(event.target.value)}
placeholder="example.com"
/>
<DomainStatusText {...{ domain }} />
<DomainStatusChecker
{...{ domain }}
isActionButtonShown={true}
isShownDetailedFail={true}
isDebounced={true}
isRetried={true}
// TODO: isRefreshed={true}
/>
</div>
);
}
1 change: 1 addition & 0 deletions src/components/Domains/TODO.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO: !! Break into more folders + utils to utils
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.AdvancedDomainsChecker {
.DomainsCombinationsChecker {
/*/
outline: 1px dotted rgb(123, 255, 0);
/**/
Expand Down
Loading