Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
7d3d609
Bump ui ver
hlib-lozhkovyi Mar 2, 2023
e1cf5a0
chore: update packages
raheelriax Mar 22, 2023
815dcb2
Merge branch 'main' into development
raheelriax Mar 22, 2023
402fb93
chore: update packages
raheelriax Mar 22, 2023
3481336
feat: add examples with callbacks
raheelriax Mar 23, 2023
0de7891
chore: update packages
raheelriax Mar 23, 2023
179b7cc
Sync ui-react
vinhnguyen1211 Mar 24, 2023
6bd468f
Sync roq/nextjs
vinhnguyen1211 Mar 24, 2023
5e20105
chat server api
praveenkokaroq Mar 24, 2023
f7f6473
change method
praveenkokaroq Mar 24, 2023
9fed6ca
added content type
praveenkokaroq Mar 24, 2023
494665d
test
praveenkokaroq Mar 24, 2023
6cb3060
Sync ui-react
vinhnguyen1211 Mar 24, 2023
100c3bf
Sync roq/nextjs & nodejs
vinhnguyen1211 Mar 24, 2023
a146eb9
Sync nextjs
vinhnguyen1211 Mar 24, 2023
6cec818
improvement(chat): CPD-2524 add chat delete filter
raheelriax Mar 27, 2023
9d21f3d
update roq package to v
praveenkokaroq Mar 28, 2023
6c8cfcd
feat(files): CPD-2529 CPD-2530 add files filter
raheelriax Mar 28, 2023
a8e0af4
feat: add profile page
raheelriax Mar 29, 2023
063ff10
Sync ui-react
vinhnguyen1211 Mar 30, 2023
1009e0b
feat:CPD-2697 make sidebar collapaseable
raheelriax Apr 4, 2023
70756cf
Sync ui-react
vinhnguyen1211 Apr 4, 2023
5d4624c
Correct chat controlled query
vinhnguyen1211 Apr 4, 2023
e4532f9
Sync ui-react
vinhnguyen1211 Apr 5, 2023
3949798
updated dev to latest nextjs package
praveenkokaroq Apr 5, 2023
bc2049b
Sync ui-react
vinhnguyen1211 Apr 5, 2023
95d1d0c
chore: update package
raheelriax Apr 6, 2023
6b0ae68
CPD-2694: updated next version
mohsinamjad Apr 12, 2023
a2c8266
chore: update @roq/ui-react
raheelriax Apr 12, 2023
ab6000c
feat(nextjs-with-roq-auth): add example to showcase
raheelriax Apr 12, 2023
497f05b
CPD-2756: updated next version
mohsinamjad Apr 13, 2023
187cee3
Merge branch 'qa02' of github.com:roqtech/roq-examples into qa02
mohsinamjad Apr 13, 2023
0885dca
CPD-2756: next release
mohsinamjad Apr 13, 2023
a70e9ec
Sync ui-react
vinhnguyen1211 Apr 14, 2023
804f7b7
CPD-2756: chat conversation redirect fix
mohsinamjad Apr 14, 2023
f202291
Merge branch 'qa02' of github.com:roqtech/roq-examples into qa02
mohsinamjad Apr 14, 2023
c930f3f
CPD-2756: version update
mohsinamjad Apr 14, 2023
56c3be4
chore: update lock file
raheelriax Apr 14, 2023
b50f9e2
chore: package update
raheelriax Apr 17, 2023
e0c79de
Update sendMessage non system
vinhnguyen1211 Apr 18, 2023
2469c20
bump package
jasper95 Apr 18, 2023
1b858cd
chore: update package
raheelriax Apr 19, 2023
e27debd
chore: update packages
raheelriax Apr 20, 2023
7d228ec
chore: update packages
raheelriax Apr 25, 2023
1948f3b
Sync ui-react
vinhnguyen1211 Apr 27, 2023
f102dff
CPD-2795: custom login test
mohsinamjad May 1, 2023
36c7c3e
CPD-2795: rc version update
mohsinamjad May 2, 2023
88cab36
Merge branch 'qa02' into bugfix/CPD-2795-custom-login-test
mohsinamjad May 2, 2023
2d4c667
Merge pull request #6 from roqtech/bugfix/CPD-2795-custom-login-test
mohsinamjad May 2, 2023
5ba6a45
CPD-2795: rc version update
mohsinamjad May 2, 2023
c38c3c5
CPD-2795: ts error fix
mohsinamjad May 2, 2023
037f224
Sync ui-react
vinhnguyen1211 May 4, 2023
359ace3
rc version pump
mohsinamjad May 8, 2023
f6e36be
rc version pump
mohsinamjad May 9, 2023
1d5e56c
rc version pump
mohsinamjad May 9, 2023
6dfb2b6
rc version pump
mohsinamjad May 9, 2023
08516db
version update
mohsinamjad May 10, 2023
0c7d418
version update
mohsinamjad May 10, 2023
696fdc4
rc version pump
mohsinamjad May 17, 2023
8592876
rc version pump
mohsinamjad Jun 5, 2023
9f8de2f
Update qa02
vinhnguyen1211 Jul 12, 2023
f42a30f
invites table locale testing
jasper95 Jul 27, 2023
3c3b023
invite current user locale
jasper95 Aug 1, 2023
1d4b285
Update qa02
vinhnguyen1211 Aug 4, 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
7,143 changes: 5,086 additions & 2,057 deletions nextjs-with-roq-auth/package-lock.json

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions nextjs-with-roq-auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@faker-js/faker": "^7.6.0",
"@next/font": "13.1.1",
"@prisma/client": "^4.10.1",
"@roq/nextjs": "^0.1.68",
"@roq/nextjs": "^1.0.17",
"bcrypt": "^5.1.0",
"eslint": "8.31.0",
"eslint-config-next": "13.1.1",
Expand All @@ -23,9 +23,12 @@
"next": "13.1.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hot-toast": "^2.4.0",
"react-select": "^5.7.2",
"swr": "^2.0.3",
"typescript": "4.9.4",
"yup": "^0.32.11"
"yup": "^0.32.11",
"zustand": "^4.3.7"
},
"devDependencies": {
"@types/bcrypt": "^5.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL,
"roqUserId" TEXT NOT NULL,
"email" TEXT NOT NULL,
"type" TEXT NOT NULL DEFAULT 'user',
"password" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "File" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"roqFileId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "File_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "User_roqUserId_key" ON "User"("roqUserId");

-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");

-- CreateIndex
CREATE UNIQUE INDEX "File_userId_roqFileId_key" ON "File"("userId", "roqFileId");
6 changes: 3 additions & 3 deletions nextjs-with-roq-auth/src/components/file/file-card.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styles from "components/file/file-card.module.css";
import Card from "components/card";
import { UserFile } from "components/file/types";
import styles from 'components/file/file-card.module.css';
import Card from 'components/card';
import { UserFile } from 'components/file/types';

export default function FileCard({ file }: { file: UserFile }) {
const { name, url, createdAt, createdByUser } = file;
Expand Down
262 changes: 219 additions & 43 deletions nextjs-with-roq-auth/src/components/file/files.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,222 @@
import useSWR, { Fetcher } from "swr";
import { routes } from "routes";
import styles from "components/file/files.module.css";
import FileCard from "components/file/file-card";
import Loader from "components/loader";
import { FilesFetchResponse } from "components/file/types";
import Card from "components/card";
import UploadFile from "components/file/upload-file";
import styles from 'components/file/files.module.css';
import Loader from 'components/loader';
import Card from 'components/card';
import UploadFile from 'components/file/upload-file';
import { useSession } from '@roq/nextjs';
import { useCallback, useEffect, useMemo, useState } from 'react';
import useSWRMutation from 'swr/mutation';
import useSWR from 'swr'
import FileCard from './file-card';
import { fileCategoriesQuery, filesQuery } from '../../graphql/queries';
import { graphqlRequest } from '../../utils/graphql-request.util';
import { UserFile } from './types';
import { SelectFilter } from './select.filter';
import { routes } from '../../routes';
import { FileInterface } from '@roq/ui-react/dist/features';

type OptionType = { label: string, value: string };
const fetcher = (url: string, options: RequestInit) => fetch(url, options).then((res) => res?.json())
export default function Files() {
const fetcher: Fetcher<FilesFetchResponse> = (apiURL: string) =>
fetch(apiURL).then((res) => res.json());

const { data, error, isLoading, mutate } = useSWR(
routes.server.files,
fetcher
);

const handleCreateSuccess = () => {
mutate();
};

const handleDelete = () => {
mutate();
};

return (
<div className={styles.feed}>
<div className={styles.uploadContainer}>
<Card>
<UploadFile onSuccess={handleCreateSuccess} onDelete={handleDelete} />
</Card>
</div>

<div className={styles.listContainer}>
{isLoading ? <Loader /> : <></>}

{data?.files?.map((f) => (
<FileCard file={f} key={f.id} />
))}

{error ? <>{JSON.stringify(error)}</> : <></>}
</div>
</div>
);
const { session } = useSession();
const [fileCategory, setFileCategory] = useState<OptionType>();
const [selectedAssociationFilter, setSelectedAssociationFilter] = useState<OptionType>();
const [selectedAssociation, setSelectedAssociation] = useState<OptionType>();
const { data: fileAssociationsData } = useSWR(routes.server.fileAssociations, fetcher);
const { trigger: createFileAssociation } = useSWRMutation(routes.server.createFileAssociation,
function <T>(url: string, { arg }: { arg: T }) {
return fetcher(url, {
method: 'POST',
body: JSON.stringify(arg)
})
});
const [filesVars, setFilesVars] = useState<{ limit?: number, offset?: number, filter?: Record<string, unknown> }>({
filter: {},
});
const {
data: files,
error,
isMutating: isLoading,
trigger: fetchFiles,
reset,
} = useSWRMutation('file', graphqlRequest);

const { data: fileCategories, trigger: fetchFileCategories } = useSWRMutation('fileCategories', graphqlRequest)


const triggerFetchFiles = useCallback(
() => {
return fetchFiles({
query: filesQuery,
responseKey: 'files',
variables: filesVars,
accessToken: session?.roqAccessToken,
})
},
[filesVars, session],
);

useEffect(() => {
if (!session?.roqAccessToken) {
return;
}
fetchFileCategories({
query: fileCategoriesQuery,
accessToken: session.roqAccessToken,
responseKey: 'fileCategories'
});
setFilesVars((vars) => ({
...vars,
limit: 10,
offset: 0,
}))
}, [session])

useEffect(() => {
if (!session?.roqAccessToken) {
return;
}
void triggerFetchFiles();
}, [filesVars])


const onOptionChange = useCallback(
(newVal: unknown) => {
const option = newVal as OptionType;
const { value } = option;
setFileCategory(option);
setSelectedAssociationFilter(null);
setFilesVars((vars) => ({
...vars,
filter: value !== 'ALL' ? {
fileCategory: { equalTo: value as string }
} : {}
}));
}, []);

const onAssociationChange = useCallback(
(newVal: unknown) => {
const option = newVal as OptionType;
setSelectedAssociationFilter(option);
if (option) {
setFileCategory(null);
}
setFilesVars((vars) => ({
...vars,
filter: option ? {
entityName: { equalTo: option.label },
entityReferences: { equalTo: option.value },
} : {}
}));
}, []);

const onLoadMore = useCallback(
() => {
setFilesVars((vars) => ({
...vars,
limit: vars.limit + 10,
}));
}, [],
);

const options = useMemo(() => {
const optionsList = fileCategories?.data
.map(({ name, key }: { name: string, key: string, }) => ({
value: key,
label: name,
}))
if (optionsList?.length) {
return [
{
label: 'All',
value: 'ALL'
},
...optionsList,
]
}
return optionsList;
}, [fileCategories]);

const fileAssociationOptions: OptionType[] = useMemo(() => {
return fileAssociationsData?.data
?.map((
{ entityName: label, entityReference: value }:
{ entityName: string, entityReference: string }
) => ({
label,
value
}));
}, [fileAssociationsData]);

const onSuccess = useCallback(
async (file: FileInterface) => {
await createFileAssociation({
fileId: file.id,
entityName: selectedAssociation.label,
entityReference: selectedAssociation.value,
})
reset();
return triggerFetchFiles();
}, [createFileAssociation, selectedAssociation, reset, triggerFetchFiles],
);


return (
<div className={styles.feed}>
<div className={styles.uploadContainer}>
<Card>
<div className="flex w-50 flex-center m5">
<SelectFilter
value={selectedAssociation}
onChange={(v) => setSelectedAssociation(v as OptionType)}
options={fileAssociationOptions}
placeholder="Upload with Associations"
isClearable={true}
prefix="Upload with"
/>
</div>
<UploadFile
onSuccess={onSuccess}
onDelete={reset}
/>
</Card>
</div>
<div className="flex w-100 space-between m5">
<div className="flex">
<SelectFilter
value={selectedAssociationFilter}
onChange={onAssociationChange}
options={fileAssociationOptions}
placeholder="Filter by Associations"
isClearable={true}
prefix="Filter by"
/>
</div>
<div className="flex">
<SelectFilter
value={fileCategory}
onChange={onOptionChange}
options={options}
placeholder="Filter by File Category"
prefix="Filter by"
/>
</div>
</div>
<div className={styles.listContainer}>
{files?.data?.map((file: UserFile) => (
<FileCard file={file} key={file.id}/>
))}

{error ? <>{JSON.stringify(error)}</> : <></>}
{isLoading ? <Loader/> : <></>}
</div>
{
files?.totalCount > files?.data?.length && (
<div className="flex flex-center mt-20">
<button disabled={isLoading} className="btn btn-sm btn-default" onClick={onLoadMore}>Load more
</button>
</div>
)
}
</div>
);
}
40 changes: 40 additions & 0 deletions nextjs-with-roq-auth/src/components/file/select.filter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import Select from 'react-select';
import { StateManagerProps } from 'react-select/dist/declarations/src/stateManager';

export const SelectFilter = (
{ value, onChange, options, prefix, ...rest }: StateManagerProps & { prefix?: string }
) => {
return (
<Select
value={value}
onChange={onChange}
isClearable={false}
isSearchable={false}
isLoading={false}
options={options}
styles={{
container: (curr) => ({
...curr,
minWidth: '200px',
}),
singleValue: (curr) => ({
...curr,
'::before': {
content: `"${prefix} "`,
}
}),
control: (cur, state) => ({
...cur,
cursor: 'pointer',
border: 'none',
borderColor: state.menuIsOpen ? 'var(--roq-user-invite-role-dropdown-boxShadow)' : '',
boxShadow: state.menuIsOpen ? '0 0 0 1px var(--roq-user-invite-role-dropdown-boxShadow)' : 'none',
}),
}}
components={{ IndicatorSeparator: () => null }}
{...rest}
/>
)

}
Loading