Merge pull request #335 from ente-io/sharable-url-patches
Sharable url patches
This commit is contained in:
commit
22ae94821c
|
@ -52,6 +52,8 @@ function CollectionShare(props: Props) {
|
|||
props.collection.key
|
||||
);
|
||||
setPublicShareUrl(t);
|
||||
} else {
|
||||
setPublicShareUrl(null);
|
||||
}
|
||||
};
|
||||
main();
|
||||
|
|
|
@ -97,8 +97,8 @@ const BannerContainer = styled.div<{ span: number }>`
|
|||
`;
|
||||
|
||||
const ReportAbuseItem = styled.div<{ span: number }>`
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
grid-column: span ${(props) => props.span};
|
||||
& > p {
|
||||
margin: 0;
|
||||
|
@ -288,7 +288,7 @@ export function PhotoList({
|
|||
item: (
|
||||
<ReportAbuseItem span={columns}>
|
||||
<LinkButton
|
||||
style={{ fontSize: '16px' }}
|
||||
style={{ fontSize: '14px' }}
|
||||
variant={ButtonVariant.danger}
|
||||
onClick={publicCollectionGalleryContext.openReportForm}>
|
||||
{constants.ABUSE_REPORT_BUTTON_TEXT}
|
||||
|
|
|
@ -226,7 +226,9 @@ export function AbuseReportForm({ show, close, url }: Iprops) {
|
|||
<Form.Group controlId="reportForm.email">
|
||||
<Form.Control
|
||||
type="text"
|
||||
placeholder={constants.ENTER_EMAIL}
|
||||
placeholder={
|
||||
constants.ENTER_EMAIL_ADDRESS
|
||||
}
|
||||
value={values.email}
|
||||
onChange={handleChange('email')}
|
||||
isInvalid={Boolean(
|
||||
|
|
|
@ -7,9 +7,7 @@ interface Iprops {
|
|||
}
|
||||
|
||||
const Info = styled.h5`
|
||||
padding: 5px 24px;
|
||||
margin: 20px;
|
||||
border-bottom: 2px solid #5a5858;
|
||||
`;
|
||||
|
||||
export function CollectionInfo(props: Iprops) {
|
||||
|
|
|
@ -10,6 +10,7 @@ const Wrapper = styled.div`
|
|||
`;
|
||||
|
||||
const NoStyleAnchor = styled.a`
|
||||
color: inherit;
|
||||
text-decoration: none !important;
|
||||
&:hover {
|
||||
color: #fff !important;
|
||||
|
@ -20,7 +21,7 @@ export const ButtonWithLink = ({
|
|||
href,
|
||||
children,
|
||||
}: React.PropsWithChildren<{ href: string }>) => (
|
||||
<Button variant="outline-success">
|
||||
<Button id="go-to-ente">
|
||||
<NoStyleAnchor href={href}>{children}</NoStyleAnchor>
|
||||
</Button>
|
||||
);
|
||||
|
|
|
@ -232,6 +232,17 @@ const GlobalStyles = createGlobalStyle`
|
|||
.btn-outline-danger, .btn-outline-secondary, .btn-outline-primary{
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
#go-to-ente{
|
||||
background:none;
|
||||
border-color: #3dbb69;
|
||||
color:#51cd7c;
|
||||
}
|
||||
#go-to-ente:hover, #go-to-ente:focus, #go-to-ente:active {
|
||||
color:#fff;
|
||||
background-color: #44774d;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ export default function Gallery() {
|
|||
const loadingBar = useRef(null);
|
||||
const [isInSearchMode, setIsInSearchMode] = useState(false);
|
||||
const [searchStats, setSearchStats] = useState(null);
|
||||
const isLoadingBarRunning = useRef(true);
|
||||
const isLoadingBarRunning = useRef(false);
|
||||
const syncInProgress = useRef(true);
|
||||
const resync = useRef(false);
|
||||
const [deleted, setDeleted] = useState<number[]>([]);
|
||||
|
|
|
@ -137,7 +137,7 @@ export default function LandingPage() {
|
|||
hash: currentURL.hash,
|
||||
}
|
||||
);
|
||||
setLoading(false);
|
||||
await initLocalForage();
|
||||
};
|
||||
|
||||
const handleNormalRedirect = async () => {
|
||||
|
@ -145,6 +145,10 @@ export default function LandingPage() {
|
|||
if (user?.email) {
|
||||
await router.push(PAGES.VERIFY);
|
||||
}
|
||||
await initLocalForage();
|
||||
};
|
||||
|
||||
const initLocalForage = async () => {
|
||||
try {
|
||||
await localForage.ready();
|
||||
} catch (e) {
|
||||
|
|
|
@ -32,7 +32,7 @@ export default function PublicCollectionGallery() {
|
|||
const token = useRef<string>(null);
|
||||
const collectionKey = useRef<string>(null);
|
||||
const url = useRef<string>(null);
|
||||
const [publicFiles, setPublicFiles] = useState<EnteFile[]>(null);
|
||||
const [publicFiles, setPublicFiles] = useState<EnteFile[]>([]);
|
||||
const [publicCollection, setPublicCollection] = useState<Collection>(null);
|
||||
const appContext = useContext(AppContext);
|
||||
const [abuseReportFormView, setAbuseReportFormView] = useState(false);
|
||||
|
@ -42,14 +42,23 @@ export default function PublicCollectionGallery() {
|
|||
const openReportForm = () => setAbuseReportFormView(true);
|
||||
const closeReportForm = () => setAbuseReportFormView(false);
|
||||
const loadingBar = useRef(null);
|
||||
const [isLoadingBarRunning, setIsLoadingBarRunning] = useState(false);
|
||||
|
||||
const openMessageDialog = () => setMessageDialogView(true);
|
||||
const closeMessageDialog = () => setMessageDialogView(false);
|
||||
|
||||
const startLoading = () => loadingBar.current?.continuousStart();
|
||||
const finishLoading = () => loadingBar.current?.complete();
|
||||
const startLoading = () => {
|
||||
!isLoadingBarRunning && loadingBar.current?.continuousStart();
|
||||
setIsLoadingBarRunning(true);
|
||||
};
|
||||
const finishLoading = () => {
|
||||
loadingBar.current?.complete();
|
||||
setIsLoadingBarRunning(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
appContext.showNavBar(true);
|
||||
setLoading(false);
|
||||
const currentURL = new URL(window.location.href);
|
||||
if (currentURL.pathname !== PAGES.ROOT) {
|
||||
router.push(
|
||||
|
@ -68,32 +77,28 @@ export default function PublicCollectionGallery() {
|
|||
const main = async () => {
|
||||
const worker = await new CryptoWorker();
|
||||
url.current = window.location.href;
|
||||
const urlS = new URL(url.current);
|
||||
const eToken = urlS.searchParams.get('t');
|
||||
const eCollectionKey = urlS.hash.slice(1);
|
||||
const decodedCollectionKey = await worker.fromHex(eCollectionKey);
|
||||
if (!eToken || !decodedCollectionKey) {
|
||||
const currentURL = new URL(url.current);
|
||||
const t = currentURL.searchParams.get('t');
|
||||
const ck = currentURL.hash.slice(1);
|
||||
const dck = await worker.fromHex(ck);
|
||||
if (!t || !dck) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
token.current = eToken;
|
||||
collectionKey.current = decodedCollectionKey;
|
||||
token.current = t;
|
||||
collectionKey.current = dck;
|
||||
url.current = window.location.href;
|
||||
const localCollection = await getLocalPublicCollection(
|
||||
eCollectionKey
|
||||
collectionKey.current
|
||||
);
|
||||
if (localCollection) {
|
||||
setPublicCollection(localCollection);
|
||||
const localPublicFiles = sortFiles(
|
||||
mergeMetadata(
|
||||
await getLocalPublicFiles(`${localCollection.id}`)
|
||||
)
|
||||
mergeMetadata(await getLocalPublicFiles(localCollection))
|
||||
);
|
||||
setPublicFiles(localPublicFiles);
|
||||
setLoading(false);
|
||||
}
|
||||
syncWithRemote();
|
||||
appContext.showNavBar(true);
|
||||
};
|
||||
main();
|
||||
}, []);
|
||||
|
@ -119,7 +124,6 @@ export default function PublicCollectionGallery() {
|
|||
setPublicFiles(null);
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
finishLoading();
|
||||
}
|
||||
};
|
||||
|
@ -132,7 +136,7 @@ export default function PublicCollectionGallery() {
|
|||
</Container>
|
||||
);
|
||||
}
|
||||
if (!publicFiles) {
|
||||
if (!isLoadingBarRunning && !publicFiles) {
|
||||
return <Container>{constants.NOT_FOUND}</Container>;
|
||||
}
|
||||
return (
|
||||
|
@ -154,7 +158,7 @@ export default function PublicCollectionGallery() {
|
|||
favItemIds={null}
|
||||
setSelected={() => null}
|
||||
selected={{ count: 0, collectionID: null }}
|
||||
isFirstLoad={false}
|
||||
isFirstLoad={true}
|
||||
openFileUploader={() => null}
|
||||
isInSearchMode={false}
|
||||
search={{}}
|
||||
|
|
|
@ -25,8 +25,16 @@ class PublicCollectionDownloadManager {
|
|||
}
|
||||
if (!this.thumbnailObjectURLPromise.get(file.id)) {
|
||||
const downloadPromise = async () => {
|
||||
const thumbnailCache = await caches.open('thumbs');
|
||||
const cacheResp: Response = await thumbnailCache.match(
|
||||
const thumbnailCache = await (async () => {
|
||||
try {
|
||||
return await caches.open('thumbs');
|
||||
} catch (e) {
|
||||
return null;
|
||||
// ignore
|
||||
}
|
||||
})();
|
||||
|
||||
const cacheResp: Response = await thumbnailCache?.match(
|
||||
file.id.toString()
|
||||
);
|
||||
if (cacheResp) {
|
||||
|
@ -35,7 +43,7 @@ class PublicCollectionDownloadManager {
|
|||
const thumb = await this.downloadThumb(token, file);
|
||||
const thumbBlob = new Blob([thumb]);
|
||||
try {
|
||||
await thumbnailCache.put(
|
||||
await thumbnailCache?.put(
|
||||
file.id.toString(),
|
||||
new Response(thumbBlob)
|
||||
);
|
||||
|
|
|
@ -18,17 +18,25 @@ const ENDPOINT = getEndpoint();
|
|||
const PUBLIC_COLLECTION_FILES_TABLE = 'public-collection-files';
|
||||
const PUBLIC_COLLECTIONS_TABLE = 'public-collections';
|
||||
|
||||
const getCollectionUID = (collection: Collection) => `${collection.id}`;
|
||||
const getCollectionUID = (collection: Collection) => `${collection.key}`;
|
||||
const getCollectionSyncTimeUID = (collectionUID: string) =>
|
||||
`public-${collectionUID}-time`;
|
||||
|
||||
export const getLocalPublicFiles = async (collectionUID: string) => {
|
||||
const localSavedPublicCollectionFiles = (
|
||||
(await localForage.getItem<LocalSavedPublicCollectionFiles[]>(
|
||||
PUBLIC_COLLECTION_FILES_TABLE
|
||||
)) ?? []
|
||||
).find(
|
||||
(localSavedPublicCollectionFiles) =>
|
||||
localSavedPublicCollectionFiles.collectionUID === collectionUID
|
||||
) || { collectionKey: null, files: [] as EnteFile[] };
|
||||
export const getLocalPublicFiles = async (collection: Collection) => {
|
||||
const localSavedPublicCollectionFiles =
|
||||
(
|
||||
(await localForage.getItem<LocalSavedPublicCollectionFiles[]>(
|
||||
PUBLIC_COLLECTION_FILES_TABLE
|
||||
)) || []
|
||||
).find(
|
||||
(localSavedPublicCollectionFiles) =>
|
||||
localSavedPublicCollectionFiles.collectionUID ===
|
||||
getCollectionUID(collection)
|
||||
) ||
|
||||
({
|
||||
collectionUID: null,
|
||||
files: [] as EnteFile[],
|
||||
} as LocalSavedPublicCollectionFiles);
|
||||
return localSavedPublicCollectionFiles.files;
|
||||
};
|
||||
export const savePublicCollectionFiles = async (
|
||||
|
@ -38,20 +46,22 @@ export const savePublicCollectionFiles = async (
|
|||
const publicCollectionFiles =
|
||||
(await localForage.getItem<LocalSavedPublicCollectionFiles[]>(
|
||||
PUBLIC_COLLECTION_FILES_TABLE
|
||||
)) ?? [];
|
||||
await localForage.setItem(PUBLIC_COLLECTION_FILES_TABLE, [
|
||||
...publicCollectionFiles,
|
||||
{ collectionUID, files },
|
||||
]);
|
||||
)) || [];
|
||||
await localForage.setItem(
|
||||
PUBLIC_COLLECTION_FILES_TABLE,
|
||||
dedupeCollectionFiles([
|
||||
{ collectionUID, files },
|
||||
...publicCollectionFiles,
|
||||
])
|
||||
);
|
||||
};
|
||||
|
||||
export const getLocalPublicCollection = async (collectionKey: string) => {
|
||||
const localCollections =
|
||||
(await localForage.getItem<Collection[]>(PUBLIC_COLLECTIONS_TABLE)) ||
|
||||
[];
|
||||
const publicCollection =
|
||||
(
|
||||
(await localForage.getItem<Collection[]>(
|
||||
PUBLIC_COLLECTIONS_TABLE
|
||||
)) ?? []
|
||||
).find(
|
||||
localCollections.find(
|
||||
(localSavedPublicCollection) =>
|
||||
localSavedPublicCollection.key === collectionKey
|
||||
) || null;
|
||||
|
@ -62,19 +72,47 @@ export const savePublicCollection = async (collection: Collection) => {
|
|||
const publicCollections =
|
||||
(await localForage.getItem<Collection[]>(PUBLIC_COLLECTIONS_TABLE)) ??
|
||||
[];
|
||||
await localForage.setItem(PUBLIC_COLLECTIONS_TABLE, [
|
||||
...publicCollections,
|
||||
collection,
|
||||
]);
|
||||
await localForage.setItem(
|
||||
PUBLIC_COLLECTIONS_TABLE,
|
||||
dedupeCollections([collection, ...publicCollections])
|
||||
);
|
||||
};
|
||||
|
||||
const dedupeCollections = (collections: Collection[]) => {
|
||||
const keySet = new Set([]);
|
||||
return collections.filter((collection) => {
|
||||
if (!keySet.has(collection.key)) {
|
||||
keySet.add(collection.key);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const dedupeCollectionFiles = (
|
||||
collectionFiles: LocalSavedPublicCollectionFiles[]
|
||||
) => {
|
||||
const keySet = new Set([]);
|
||||
return collectionFiles.filter(({ collectionUID }) => {
|
||||
if (!keySet.has(collectionUID)) {
|
||||
keySet.add(collectionUID);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getPublicCollectionLastSyncTime = async (collectionUID: string) =>
|
||||
(await localForage.getItem<number>(`public-${collectionUID}-time`)) ?? 0;
|
||||
(await localForage.getItem<number>(
|
||||
getCollectionSyncTimeUID(collectionUID)
|
||||
)) ?? 0;
|
||||
|
||||
const setPublicCollectionLastSyncTime = async (
|
||||
collectionUID: string,
|
||||
time: number
|
||||
) => await localForage.setItem(collectionUID, time);
|
||||
) => await localForage.setItem(getCollectionSyncTimeUID(collectionUID), time);
|
||||
|
||||
export const syncPublicFiles = async (
|
||||
token: string,
|
||||
|
@ -83,9 +121,7 @@ export const syncPublicFiles = async (
|
|||
) => {
|
||||
try {
|
||||
let files: EnteFile[] = [];
|
||||
const localFiles = await getLocalPublicFiles(
|
||||
getCollectionUID(collection)
|
||||
);
|
||||
const localFiles = await getLocalPublicFiles(collection);
|
||||
files.push(...localFiles);
|
||||
try {
|
||||
if (!token) {
|
||||
|
|
|
@ -627,19 +627,20 @@ const englishConstants = {
|
|||
MALICIOUS_CONTENT: 'contains malicious content',
|
||||
COPYRIGHT:
|
||||
'infringes on the copyright of someone I am authorized to represent',
|
||||
SELECT_REASON: 'select a reason',
|
||||
ENTER_FULL_NAME: 'full name',
|
||||
ENTER_EMAIL_ADDRESS: 'email*',
|
||||
SELECT_REASON: 'select a reason*',
|
||||
ENTER_FULL_NAME: 'full name*',
|
||||
ENTER_DIGITAL_SIGNATURE:
|
||||
'typing your full name in this box will act as your digital signature',
|
||||
ENTER_ON_BEHALF_OF: 'I am reporting on behalf of',
|
||||
ENTER_ADDRESS: 'address',
|
||||
ENTER_JOB_TITLE: 'job title',
|
||||
ENTER_CITY: 'city',
|
||||
ENTER_PHONE: 'phone number',
|
||||
'typing your full name in this box will act as your digital signature*',
|
||||
ENTER_ON_BEHALF_OF: 'I am reporting on behalf of*',
|
||||
ENTER_ADDRESS: 'address*',
|
||||
ENTER_JOB_TITLE: 'job title*',
|
||||
ENTER_CITY: 'city*',
|
||||
ENTER_PHONE: 'phone number*',
|
||||
|
||||
ENTER_STATE: 'state',
|
||||
ENTER_POSTAL_CODE: 'zip/postal code',
|
||||
ENTER_COUNTRY: 'country',
|
||||
ENTER_STATE: 'state*',
|
||||
ENTER_POSTAL_CODE: 'zip/postal code*',
|
||||
ENTER_COUNTRY: 'country*',
|
||||
JUDICIAL_DESCRIPTION: () => (
|
||||
<>
|
||||
By checking the following boxes, I state{' '}
|
||||
|
|
Loading…
Reference in a new issue