I just upgraded my RN project to RN 0.52 and the react-native fbsdk was not working correctly so I changed my import structure from:
const FBSDK = require('react-native-fbsdk');
const {
LoginManager,
AccessToken,
GraphRequest,
GraphRequestManager
} = FBSDK;
To
import { LoginManager,
AccessToken,
GraphRequest,
GraphRequestManager } from 'react-native-fbsdk';
full source code:
import React, { Component } from 'react';
import { View, ActivityIndicator, FlatList, Image, TouchableHighlight, StatusBar, Alert} from 'react-native';
import styles from './styles';
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Container, Header, Content, Button, Text, Spinner, Title } from 'native-base';
import { requestBusiness, receiveBusiness, storeLoginScreenId, receiveAwsId } from '../../actions'
import { withApollo, ApolloClient, graphql } from 'react-apollo';
import gql from 'graphql-tag';
var AWS = require('aws-sdk/dist/aws-sdk-react-native');
import { LoginManager,
AccessToken,
GraphRequest,
GraphRequestManager } from 'react-native-fbsdk';
class Login extends Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
isLoggedIn: PropTypes.bool.isRequired,
isFetching: PropTypes.bool.isRequired,
client: PropTypes.instanceOf(ApolloClient).isRequired
}
_handleFacebookLogin(navigation, dispatch, client, isFetching) {
//const { navigation } = this.props
//LoginManager.logOut();
LoginManager.logInWithReadPermissions(["business_management","pages_show_list"]).then(
function (result) {
if (result.isCancelled) {
Alert.alert(
'Facebook Permissions issue')
} else {
//alert('Login success with permissions: ' + result.grantedPermissions.toString())
AccessToken.getCurrentAccessToken().then(
(data) => {
AWS.config.region = 'us-east-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'xxxxxxxxxxxxxxx',
Logins: {
'graph.facebook.com': data.accessToken.toString()
}
}
);
AWS.config.credentials.clearCachedId();
AWS.config.credentials.get(function(err) {
if (err){ alert("Error" + err);
console.log(err);
}
dispatch(requestBusiness())
client.query({
query: gql`query getCurrentUser($Id: String!) {
User(id: $Id) {
id,
posts {
postId,
postText
}
}
}
}`,
variables: {Id: AWS.config.credentials.identityId},
fetchPolicy: 'network-only'
}).then((result) => {
dispatch(receiveAwsId(AWS.config.credentials.identityId))
dispatch(receiveBusiness())
if(result.data.businessUser != null){
navigation.dispatch({ type: 'LOGGEDIN' });
}
else {
navigation.dispatch({ type: 'ONBOARD' });
}
}).catch((err) => {
console.log('catch', err)
});
});
}
)
//navigation.dispatch({ type: 'LOGIN' });
}
},
function (error) {
alert('Login fail with error: ' + error)
console.log(error)
}
)
}
componentWillReceiveProps(nextProps) {
/*
const { business, navigation, isFetching, dispatch } = this.props
if(nextProps.isFetching == false && isFetching == true){
if(nextProps.business == null && business == undefined){
navigation.dispatch({ type: 'ONBOARD' });
} else {
navigation.dispatch({ type: 'LOGIN' });
}
}*/
}
render() {
const {navigation, dispatch, isFetching, client} = this.props
return (
<Container style={styles.container}>
<Text></Text>
<Title>
<Title style={styles.title}>App</Title>
<Title style={styles.secondaryTitle}>Login</Title>
</Title>
{isFetching ? <Spinner color='#FFFFFF' /> :
<Button bordered rounded light
style={styles.loginButton}
onPress={() => this._handleFacebookLogin(navigation, dispatch, client, isFetching)}>
<Text>Login With Facebook</Text>
</Button>}
</Container>
);
}
}
const LoginComponentWithApollo = withApollo(Login)
const mapStateToProps = state => {
const { business } = state
const {
businessInfo,
lastUpdated,
isFetching
} = business
return {
isLoggedIn : state.isLoggedIn,
dispatch : state.dispatch,
businessInfo,
lastUpdated,
isFetching
}
}
export default connect(mapStateToProps)(LoginComponentWithApollo);
psckage.json:
{
"name": "MyApp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"aws-sdk": "^2.130.0",
"native-base": "^2.3.9",
"prop-types": "^15.6.0",
"react": "^16.2.0",
"react-apollo": "^1.4.16",
"react-native": "^0.52.1",
"react-native-code-push": "^5.1.2-beta",
"react-native-fbsdk": "^0.7.0",
"react-native-onesignal": "^3.0.6",
"react-native-sentry": "^0.26.0",
"react-native-vector-icons": "^4.4.0",
"react-navigation": "^1.0.0-beta.13",
"react-redux": "^5.0.5",
"redux": "^3.7.2",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.2.0"
},
"devDependencies": {
"babel-jest": "20.0.3",
"babel-preset-react-native": "2.1.0",
"jest": "20.0.4",
"react-test-renderer": "16.0.0-alpha.12"
},
"jest": {
"preset": "react-native"
},
"rnpm": {
"assets": [
"./assets/fonts/"
]
}
}
^^ I am getting the following error:
Cannot read property 'loginWithReadPermissions' of undefined.
Any idea what might be causing this? when I go into the react-native-fbdsk I do see that these functions are defined in there.
Related
Before update my expo project to SDK 47, all test suites worked as a charm. But now I'm getting these kind of errors that I don't know how to solve it.
I've noticed those packages are written now with TS. Maybe the error is going around this. Do I need to change something in order to make packages with TS work?
Here are the versions that I'm using:
"devDependencies": {
"#babel/core": "^7.19.3",
"#babel/plugin-proposal-optional-chaining": "^7.16.7",
"#types/react-native": "~0.70.6",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.3",
"babel-plugin-module-resolver": "^4.1.0",
"babel-preset-expo": "~9.2.1",
"concurrently": "^7.2.2",
"deprecated-react-native-prop-types": "^2.3.0",
"eslint": "^7.32.0",
"eslint-plugin-jest": "^24.7.0",
"eslint-plugin-react": "^7.29.4",
"husky": "^6.0.0",
"jest-expo": "^47.0.1",
"jest-json": "^1.1.1",
"postcss": "^8.4.14",
"react-native-jest-mocks": "^1.5.0",
"tailwindcss": "^3.1.4"
}
My jest config
"jest": {
"preset": "jest-expo",
"transformIgnorePatterns": [
"node_modules/(?!(jest-)?react-native|unimodules-permissions-interface|react-clone-referenced-element|#react-native(-community)?|expo(nent)?|#expo(nent)?/.*|react-navigation|#react-navigation/.*|#unimodules/.*|sentry-expo|native-base|#codler/react-native-keyboard-aware-scroll-view|react-native-paper|react-native-paper/.*|expo-modules-core|expo-modules-core/.*|)"
],
"setupFiles": [
"./jest-setup.js"
],
"setupFilesAfterEnv": [
"jest-json"
]
}
Any idea? I'd aprreciate your help.
UPDATE
This is an example test.
import Home from './Home';
import React from 'react';
import {
cleanup,
render,
} from '#testing-library/react-native';
import axios from 'axios';
import { Alert } from 'react-native';
import { MockedNavigator, waitFor } from '../../../helpers/testing';
jest.mock('axios');
jest.mock('./Home', () => './Home');
const mockedNavigate = jest.fn();
jest.mock("#react-navigation/native", () => {
const actualNav = jest.requireActual("#react-navigation/native");
return {
...actualNav,
useNavigation: () => ({
navigate: mockedNavigate,
dispatch: jest.fn(),
addListener: jest.fn(),
removeListener: jest.fn(),
}),
};
});
beforeAll(() => {
// Home uses fetch to reload the user, so mock fetch to return a
// fake user
global.fetch = jest.fn().mockResolvedValue({
status: 200,
ok: true,
json: () => Promise.resolve({ data: { user: {} } }),
});
});
afterEach(cleanup);
const setup = async () => {
return render(
<MockedNavigator
routes={[
{ name: 'Home', component: Home },
]}
/>
);
};
describe('API', () => {
test('Shows error when the request can not be completed', async () => {
axios.get.mockRejectedValue({
response: { data: undefined, status: 500 },
});
// Mock alert
Alert.alert = jest.fn();
await setup();
await waitFor(() => {
expect(Alert.alert).toHaveBeenCalledWith('Error', expect.any(String));
});
});
});
I've already have react-native-paper as a Provider, in my MockedNavigator as follows:
export const MockedNavigator = ({ routes }) => {
const { Screen, Navigator } = createStackNavigator();
return (
<NavigationContainer>
<Providers>
<ReservationProvider>
<Navigator>
{routes.map((props, index) => (
<Screen
key={index}
{...props}
/>
))}
</Navigator>
</ReservationProvider>
</Providers>
</NavigationContainer>
);
};
export const Providers = ({ children }) => (
<NotificationProvider>
<GeolocationProvider>
<SettingsProvider>
<OAuthProvider>
<TailwindProvider>
<ThemeProvider>
<PortalProvider>
<CalendarProvider>
<ForegroundNotification />
{children}
</CalendarProvider>
</PortalProvider>
</ThemeProvider>
</TailwindProvider>
</OAuthProvider>
</SettingsProvider>
</GeolocationProvider>
</NotificationProvider>
);
export const ThemeProvider = ({ children }) => {
const [themeWithFont, setThemeWithFont] = useState(theme);
useEffect(() => {
const loadFonts = async () => {
setThemeWithFont({
...theme,
fonts: {
...theme.fonts,
medium: { fontFamily: C.fontFamilyDefault },
}
});
};
loadFonts();
}, []);
return <PaperProvider theme={themeWithFont}>{children}</PaperProvider>;
};
import { Provider as PaperProvider } from 'react-native-paper';
I am trying to integrate Coinbase oauth2 to my react-native expo app. I have followed the below guide: https://docs.expo.dev/guides/authentication/#coinbase
Below is my app.json
{
"expo": {
"name": "My App",
"slug": "my-app",
"privacy": "public",
"platforms": [
"ios",
"android",
"web"
],
"version": "1.1.13",
"facebookScheme": "fbxxxxxxxxxxxx",
"facebookAppId": "xxxxxxxxxxxxxxxxxxxx",
"facebookDisplayName": "Ubuntu",
"orientation": "portrait",
"icon": "./assets/app_logo.png",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "cover",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.package.app",
"infoPlist": {
"NSCameraUsageDescription": "This app uses the camera to upload documents."
},
"googleServicesFile": "./GoogleService-Info.plist",
"usesIcloudStorage": true
},
"android": {
"package": "com.package.app",
"useNextNotificationsApi": true
},
"web": {
"build": {
"babel": {
"include": [
"static-container"
]
}
}
},
"scheme": "com.package.app"
}
}
App.native.js
import {
exchangeCodeAsync,
makeRedirectUri,
TokenResponse,
useAuthRequest
} from "expo-auth-session";
import * as WebBrowser from "expo-web-browser";
import * as React from "react";
import { Button, View } from "react-native";
WebBrowser.maybeCompleteAuthSession();
// Endpoint
const discovery = {
authorizationEndpoint: "https://www.coinbase.com/oauth/authorize",
tokenEndpoint: "https://api.coinbase.com/oauth/token",
revocationEndpoint: "https://api.coinbase.com/oauth/revoke",
};
const redirectUri = makeRedirectUri({
// scheme: 'com.package.app',
// path: 'redirect',
native: 'com.package.app://redirect',
useProxy: false
});
const CLIENT_ID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const CLIENT_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
export default function App() {
const [request, response, promptAsync] = useAuthRequest(
{
clientId: CLIENT_ID,
scopes: ["wallet:accounts:read"],
redirectUri // -> tried this as well redirectUri: 'urn:ietf:wg:oauth:2.0:oob'
},
discovery
);
const {
// The token will be auto exchanged after auth completes.
token,
exchangeError,
} = useAutoExchange(
response?.type === "success" ? response.params.code : null
);
React.useEffect(() => {
if (token) {
console.log("My Token:", token.accessToken);
}
}, [token]);
return (
<View style={{ marginTop: 300,}}>
<Button
disabled={!request}
title="Login"
onPress={() => {
promptAsync();
}}
/>
</View>
);
}
// A hook to automatically exchange the auth token for an access token.
// this should be performed in a server and not here in the application.
// For educational purposes only:
function useAutoExchange(code) {
const [state, setState] = React.useReducer(
(state, action) => ({ ...state, ...action }),
{ token: null, exchangeError: null }
);
const isMounted = useMounted();
React.useEffect(() => {
if (!code) {
setState({ token: null, exchangeError: null });
return;
}
exchangeCodeAsync(
{
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
code,
redirectUri,
},
discovery
)
.then((token) => {
if (isMounted.current) {
setState({ token, exchangeError: null });
}
})
.catch((exchangeError) => {
if (isMounted.current) {
setState({ exchangeError, token: null });
}
});
}, [code]);
return state;
}
function useMounted() {
const isMounted = React.useRef(true);
React.useEffect(() => {
return () => {
isMounted.current = false;
};
}, []);
return isMounted;
}
I have added com.package.app to the permitted redirect URL as well.
Does anyone help me find why am I still getting 'The redirect URI included is not valid'?
Expo SDK version: 43
Developing platform: Windows
Packages used:
"expo-auth-session": "~3.4.2"
"expo-web-browser": "~10.0.3"
"react": "17.0.0"
"react-native": "0.64.3"
Thank you.
I am building a project and want to store the session's data in MongoDB with the help of ApolloServer, Express, GraphQL
However, I am unable to set the cookie on the browser (Chrome & Firefox)
Initially, I had a few CORS errors, I believe I fixed them
The session data and ID are being stored in MongoDB successfully
When I log in and run the "me" query to check if the cookie was set, it returns null as in nothing was set
Please help me
index.js
import "reflect-metadata";
import { MikroORM } from "#mikro-orm/core";
import { ApolloServer } from "apollo-server-express";
import express from "express";
import { buildSchema } from "type-graphql";
import mikroOrmConfig from "./mikro-orm.config";
import { HelloResolver } from "./resolvers/hello";
import { PostResolver } from "./resolvers/post";
import { UserResolver } from "./resolvers/user";
import session from "express-session";
import MongoStore from "connect-mongo";
import { __prod__ } from "./constants";
import { MyContext } from "./types";
const main = async () => {
const orm = await MikroORM.init(mikroOrmConfig);
await orm.getMigrator().up();
const app = express();
const corsOptions = {
origin: 'https://studio.apollographql.com',
credentials: true
}
app.set("trust proxy", 1);
app.use(
session({
name: "qid",
secret: "secret",
saveUninitialized: false,
resave: false,
store: MongoStore.create({
mongoUrl: "mongodb://localhost/test-app",
touchAfter: 24 * 3600, // time period in seconds
}),
cookie: {
maxAge: 3600 * 60 *30 * 24 * 3600,
secure: true,
httpOnly: true,
sameSite: 'lax'
}
})
);
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [HelloResolver, PostResolver, UserResolver],
validate: false,
}),
context: ({ req, res }): MyContext => ({ em: orm.em.fork(), req, res }),
});
await apolloServer.start();
apolloServer.applyMiddleware({ app, cors: corsOptions });
app.listen(4000, () => {
console.log("server started on port 4000");
});
};
package.json
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"#types/connect-mongo": "^3.1.3",
"#types/express": "^4.17.13",
"#types/express-session": "^1.17.4",
"#types/mongodb": "^4.0.7",
"#types/node": "^16.7.2",
"express-session": "^1.17.2",
"nodemon": "^2.0.12",
"ts-node": "^10.2.1",
"typescript": "^4.3.5"
},
"dependencies": {
"#mikro-orm/cli": "^4.5.9",
"#mikro-orm/core": "^4.5.9",
"#mikro-orm/migrations": "^4.5.9",
"#mikro-orm/postgresql": "^4.5.9",
"apollo-server-express": "^3.3.0",
"argon2": "^0.28.2",
"connect-mongo": "^4.5.0",
"express": "^4.17.1",
"graphql": "^15.5.1",
"pg": "^8.7.1",
"reflect-metadata": "^0.1.13",
"type-graphql": "^1.1.1"
},
"mikro-orm": {
"configPaths": [
"./sr/mikro-orm.config.ts",
"./dist/mikro-orm.config.js"
]
}
user.ts login Mutation
#Mutation(() => UserResponse)
async login(
#Arg("options", () => UsernamePasswordInput) options: UsernamePasswordInput,
#Ctx() { em, req }: MyContext
): Promise<UserResponse> {
const user = await em.findOne(User, { username: options.username });
if (!user) {
return {
errors: [
{
field: "username",
message: "Invalid Username",
},
],
};
}
const valid = await argon2.verify(user.password, options.password);
if (!valid) {
return {
errors: [
{
field: "password",
message: "Invalid Password",
},
],
};
}
req.session.userId = user.id;
return {
user,
};
}
user.ts me Query
#Query(() => User, {nullable: true})
async me(
#Ctx() { req, em }: MyContext,
){
if(!req.session.userId){
return null;
}
else {
const user = await em.findOne(User, { id: req.session.userId });
return user;
}
}
The context
import { EntityManager, IDatabaseDriver, Connection } from "#mikro-orm/core";
import { Request, Response } from "express";
import { Session } from 'express-session';
export interface MyContext {
em: EntityManager<any> & EntityManager<IDatabaseDriver<Connection>>;
req: Request & { session?: Session & { userId?: number }};
res: Response;
};
Session data getting stored in MongoDB
ApolloGraphQL, the user is null even after login
Please help me or give me some pointers if I have made any mistakes, Thank You!
I am trying to implement avatar upload in Next.js blog with Node.js server using Apollo client + apollo-upload-client on client side and apollo-express-server on server side.
I've got the next error:
POST body missing. Did you forget use body-parser middleware?
I am sure that I have body parser on my server.
Server.ts
import "reflect-metadata";
import "dotenv-safe/config";
import 'module-alias/register';
import { __prod__ } from "#/config/config";
import express from "express";
import Redis from "ioredis";
import session from "express-session";
import connectRedis from "connect-redis";
import { createConnection } from "typeorm";
import { User } from "#/entities/User";
import { Project } from "#/entities/Project";
import path from "path";
const server = async () => {
await createConnection({
type: "postgres",
url: process.env.DATABASE_URL,
logging: true,
migrations: [path.join(__dirname, "./migrations/*")],
entities: [User, Project]
});
const app = express();
require("#/start/logger"); // log exceptions
const RedisStore = connectRedis(session); // connect redis store
const redis = new Redis(process.env.REDIS_URL);
require("#/start/apolloServer")(app, redis); // create apollo server
require("#/start/appConfig")(app,redis,RedisStore) // configure app
const PORT = process.env.PORT || 3007;
app.listen(PORT, () => {
console.log(`🚀 Server Started at PORT: ${PORT}`);
});
};
server().catch((err) => {
console.error(err);
});
My Apollo Server
I use apollo-server-express
import { ApolloServer, gql } from "apollo-server-express";
import { buildSchema } from "type-graphql";
import ProfilePictureResolver from "#/resolvers/upload";
import { createUserLoader } from "#/utils/createUserLoader";
import { UserResolver } from "#/resolvers/user";
import { ProjectResolver } from "#/resolvers/project";
import {Express} from "express";
import { Redis } from "ioredis";
const typeDefs = gql`
scalar Upload
type File {
id: ID!
filename: String!
mimetype: String!
path: String!
}
type Mutation {
singleUpload(file: Upload!): File!
}
`;
module.exports = async function(app:Express,redis:Redis){
const apolloServer = new ApolloServer({
typeDefs,
schema: await buildSchema({
resolvers: [UserResolver, ProjectResolver, ProfilePictureResolver],
validate: false,
}),
context: ({ req, res }) => ({
req,
res,
redis,
userLoader: createUserLoader()
}),
uploads: false
});
apolloServer.applyMiddleware({
app,
cors: false,
});
}
Resolver:
import { Resolver, Mutation, Arg } from 'type-graphql'
import { GraphQLUpload, FileUpload } from 'graphql-upload'
import os from 'os'
import { createWriteStream } from 'fs'
import path from 'path'
#Resolver()
export default class SharedResolver {
#Mutation(() => Boolean)
async uploadImage(
#Arg('file', () => GraphQLUpload)
file: FileUpload
): Promise<Boolean> {
const { createReadStream, filename } = await file
const destinationPath = path.join(os.tmpdir(), filename)
const url = await new Promise((res, rej) =>
createReadStream()
.pipe(createWriteStream(destinationPath))
.on('error', rej)
.on('finish', () => {
//stuff to do
})
);
return true;
}
}
Server config
import {Express} from 'express'
import { __prod__, COOKIE_NAME } from "#/config/config";
import cors from "cors";
import session from "express-session";
import { Redis } from 'ioredis';
import { RedisStore } from 'connect-redis';
import { bodyParserGraphQL } from 'body-parser-graphql'
module.exports = function(app:Express, redis:Redis, RedisStore:RedisStore){
app.set("trust proxy", 1);
app.use(bodyParserGraphQL());
app.use(
cors({
origin: process.env.CORS_ORIGIN,
credentials: true,
})
);
app.use(
session({
name: COOKIE_NAME,
store: new RedisStore({
client: redis,
disableTouch: true,
}),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10, // 10 years
httpOnly: true,
sameSite: "lax",
secure: __prod__,
domain: __prod__ ? ".heroku.com" : undefined,
},
saveUninitialized: false,
secret: process.env.SESSION_SECRET,
resave: false,
})
);
}
Client
App client
import { createWithApollo } from "#/utils/createWithApollo";
import { ApolloClient, InMemoryCache } from "#apollo/client";
import { NextPageContext } from "next";
import { createUploadLink } from 'apollo-upload-client';
const createClient = (ctx: NextPageContext) =>
new ApolloClient({
credentials: "include",
headers: {
cookie:
(typeof window === "undefined"
? ctx?.req?.headers.cookie
: undefined) || "",
},
cache: new InMemoryCache({
typePolicies: {
Query: {}
}
}),
link: createUploadLink({uri:'http://localhost:4000/graphql'})
});
// const createClient: ApolloClient<NormalizedCacheObject> = new ApolloClient({
// cache: new InMemoryCache({}),
// uri: 'http://localhost:4000/graphql'
// });
export const withApollo = createWithApollo(createClient);
Query
import { gql } from '#apollo/client';
export const UPLOAD_IMAGE_MUTATION = gql`
mutation uploadImage($file: Upload!) {
uploadImage(file: $file)
}
`;
Page
import React, {useState} from 'react';
import {useSelector} from "react-redux";
import {Box} from "#/components/UI/Box/Box"
import {Header} from "#/components/UI/Text/Header"
import { withApollo } from "#/utils/withApollo";
import withPrivateRoute from "#/HOC/withPrivateRoute";
import { useMutation } from "#apollo/react-hooks";
import { UPLOAD_IMAGE_MUTATION } from "#/graphql/mutations/uploadImage";
interface IProps{};
const Profile:React.FC<IProps> = () => {
const user = useSelector(state => state.user);
const [file, setFileToUpload] = useState(null);
const [uploadImage, {loading}] = useMutation(UPLOAD_IMAGE_MUTATION);
const onAvatarUpload = (e) =>{
setFileToUpload(e.target.files[0]);
}
const onSubmit = async (e) =>{
e.preventDefault();
const response = await uploadImage({
variables: {file}
});
}
return (
<Box mt={20} pl={30} pr={30}>
<Header>
Edit Profile
</Header>
<input onChange={onAvatarUpload} type="file" placeholder="photo" />
<button onClick={(e)=>onSubmit(e)}>Submit</button>
</Box>
)
};
export default withApollo({ ssr: false })(withPrivateRoute(Profile, true));
My Client package:
{
"name": "app",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"#apollo/client": "^3.2.5",
"#apollo/react-hooks": "^4.0.0",
"apollo-upload-client": "^14.1.3",
"graphql": "^15.4.0",
"graphql-tag": "^2.11.0",
"graphql-upload": "^11.0.0",
"isomorphic-unfetch": "^3.1.0",
"next": "^9.5.5",
"next-apollo": "^5.0.3",
"next-redux-wrapper": "^6.0.2",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react-is": "^16.13.1",
"react-redux": "^7.2.2",
"redux": "^4.0.5",
"styled-components": "^5.2.1",
"urql": "^1.10.3",
"uuid": "^8.3.1"
},
"devDependencies": {
"#testing-library/jest-dom": "^5.11.5",
"#testing-library/react": "^11.1.1",
"#types/graphql": "^14.5.0",
"#types/jest": "^26.0.15",
"#types/next": "^9.0.0",
"#types/node": "^14.0.27",
"#types/react": "^16.9.55",
"#types/react-dom": "^16.9.9",
"#types/styled-components": "^5.1.4",
"#types/uniqid": "^5.2.0",
"#types/uuid": "^8.3.0",
"#welldone-software/why-did-you-render": "^5.0.0",
"babel-plugin-inline-react-svg": "^1.1.2",
"babel-plugin-module-resolver": "^4.0.0",
"babel-plugin-styled-components": "^1.11.1",
"redux-devtools-extension": "^2.13.8",
"typescript": "^4.0.5"
}
}
Server package:
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "server.ts",
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"nodemon": "nodemon dist/server.js",
"dev": "npm-run-all --parallel watch nodemon",
"start": "ts-node src/server.ts",
"client": "cd ../ && npm run dev --prefix client",
"runall": "npm-run-all --parallel client dev",
"typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js",
"migration:up": "typeorm migration:run",
"migration:down": "typeorm migration:revert",
"migration:generate": "typeorm migration:generate -n 'orm_migrations'"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"apollo-server-express": "^2.16.1",
"argon2": "^0.26.2",
"connect-redis": "^5.0.0",
"cors": "^2.8.5",
"dataloader": "^2.0.0",
"dotenv-safe": "^8.2.0",
"express": "^4.17.1",
"express-async-errors": "^3.1.1",
"express-session": "^1.17.1",
"graphql": "^15.3.0",
"ioredis": "^4.17.3",
"module-alias": "^2.2.2",
"path": "^0.12.7",
"pgtools": "^0.3.0",
"reflect-metadata": "^0.1.13",
"type-graphql": "^1.0.0-rc.3",
"typeorm": "^0.2.25",
"uuid": "^8.3.0",
"winston": "^3.3.3"
},
"devDependencies": {
"#types/connect-redis": "0.0.14",
"#types/cors": "^2.8.8",
"#types/express": "^4.17.8",
"#types/express-session": "^1.17.0",
"#types/graphql": "^14.5.0",
"#types/ioredis": "^4.17.7",
"#types/node": "^8.10.66",
"#types/nodemailer": "^6.4.0",
"#types/pg": "^7.14.6",
"#types/uuid": "^8.3.0",
"gen-env-types": "^1.0.4",
"nodemon": "^2.0.6",
"npm-run-all": "^4.1.5",
"pg": "^8.4.2",
"ts-node": "^8.10.2",
"typescript": "^3.9.7"
},
"_moduleAliases": {
"#": "dist/"
}
}
NOTE!
When I try to remove uploads: false from apolloServer configuration I receive another error:
"Variable "$file" got invalid value {}; Upload value invalid."
And indeed in form data I see
------WebKitFormBoundarybNufV7QLX3EU1SN6 Content-Disposition: form-data; name="operations"
{"operationName":"uploadImage","variables":{"file":null},"query":"mutation
uploadImage($file: Upload!) {\n uploadImage(file: $file)\n}\n"}
------WebKitFormBoundarybNufV7QLX3EU1SN6 Content-Disposition: form-data; name="map"
{"1":["variables.file"]}
------WebKitFormBoundarybNufV7QLX3EU1SN6 Content-Disposition: form-data; name="1"; filename="Screen Shot 2020-11-20 at 17.56.14.png"
Content-Type: image/png
------WebKitFormBoundarybNufV7QLX3EU1SN6--
I am 100% sure that I pass the file.
I faced the same problem in my NextJs project, I found that the resolver of Upload checks if the value is instanceOf Upload, and that is somehow not working.
I fix it by creating my own resolver without using the 'graphql-upload' package like this:
Solution 1 :
export const resolvers: Resolvers = {
Upload: new GraphQLScalarType({
name: 'Upload',
description: 'The `Upload` scalar type represents a file upload.',
parseValue(value) {
return value;
},
parseLiteral(ast) {
throw new GraphQLError('Upload literal unsupported.', ast);
},
serialize() {
throw new GraphQLError('Upload serialization unsupported.');
},
})
};
Solution 2 :
Or you can just don't declare any resolver for this type.
Note:
Be sure that you declared scalar type of Upload in your schema and you need to add the uploads field to your Apollo Server configuration:
const apolloServer = new ApolloServer({
uploads: {
maxFileSize: 10000000, // 10 MB
maxFiles: 20
},
.
.
.
What is the corect way to import vue packages in laravel 5.6? It comes with vue and bootstrap preinstall. I see they are all compile in app.js from public directory but I can figure out how to import https://github.com/moreta/vue-search-select and use it. After I tried to import it on my own:
Error:
ncaught TypeError: Vue.component is not a function
At line:
Vue.component('search-user', __webpack_require__(42));
Until now I tried this:
assets/js/bootstrap.js:
import { BasicSelect } from 'vue-search-select';
window.BasicSelect = BasicSelect;
assets/js/app.js:
require('./bootstrap');
window.Vue = require('vue');
window.Vue = require('vue-search-select');
Vue.component('search-user', require('./components/SearchUser.vue'));
var app = new Vue({
el: '#app'
})
components
<template>
<basic-select :options="options"
:selected-option="item"
placeholder="select item"
#select="onSelect">
</basic-select>
</template>
<script>
export default {
data() {
return {
keywords: null,
options: []
};
},
watch: {
keywords(after, before) {
if (this.keywords.length > 0)
this.fetch();
}
},
methods: {
fetch() {
axios.get('/api/search', {params: {keywords: this.keywords}})
.then(response => this.options = response.data)
.catch(error => {
});
},
onSelect (item) {
this.item = item
},
reset () {
this.item = {}
},
selectOption () {
// select option from parent component
this.item = this.options[0]
},
components: {
BasicSelect
}
}
}
</script>
I ran: npm install and npm run watch:
"devDependencies": {
"ajv": "^6.0.0",
"bootstrap": "^4.0.0",
"cross-env": "^5.1",
"laravel-mix": "^2.0",
"lodash": "^4.17.4",
"popper.js": "^1.12",
"uikit": "^3.0.0-beta.35",
"vue": "^2.5.7",
"vue-search-select": "^2.5.0"
},
"dependencies": {
"axios": "^0.17.1",
"jquery": "^3.3.1"
}
I think that the simple will do
window.Vue = require('vue');
require('vue-search-select');
Then in your components you can import what you need on top:
import { BasicSelect } from 'vue-search-select';
export default {
data() {
return {
keywords: null,
options: [],
item: null
};
},
...
One missing detail that tricked me with this one, you need to register the components like this, otherwise it won't be found:
components: {
ModelSelect,
BasicSelect
},