mirror of
https://github.com/muerwre/muerwre.github.io.git
synced 2025-04-25 02:46:39 +07:00
added whole content
This commit is contained in:
parent
1b5df685cb
commit
8b25e0631a
70 changed files with 5962 additions and 19 deletions
48
content/Frontend/React Native/OAuth2 login.md
Normal file
48
content/Frontend/React Native/OAuth2 login.md
Normal file
|
@ -0,0 +1,48 @@
|
|||
Use #oauth2 login with React-Native
|
||||
|
||||
## Common OAuth2 providers
|
||||
|
||||
Can be handled by [react-native-app-auth](react-native-app-auth) by redirecting to url `com.yourapp://oauth2provider`.
|
||||
|
||||
### Example for #Google
|
||||
|
||||
```typescript
|
||||
import { authorize } from 'react-native-app-auth';
|
||||
|
||||
const GOOGLE_OAUTH_CLIENT = '...';
|
||||
|
||||
// ...
|
||||
const authState = await authorize({
|
||||
issuer: 'https://accounts.google.com',
|
||||
clientId: `${GOOGLE_OAUTH_CLIENT}.apps.googleusercontent.com`,
|
||||
redirectUrl: `com.yourapp:/oauth2redirect/google`,
|
||||
scopes: ['openid', 'profile'],
|
||||
dangerouslyAllowInsecureHttpRequests: true,
|
||||
});
|
||||
```
|
||||
|
||||
### Example for #Yandex
|
||||
|
||||
```typescript
|
||||
const YANDEX_OAUTH_CLIENT = '...';
|
||||
const YANDEX_OAUTH_SECRET = '...'; // better hide it somehow
|
||||
const APP_ID = 'com.yourapp';
|
||||
|
||||
const authState = await authorize({
|
||||
serviceConfiguration: {
|
||||
authorizationEndpoint: `https://oauth.yandex.ru/authorize?response_type=code&client_id=${YANDEX_OAUTH_CLIENT}&redirect_uri=${APP_ID}:/oauth2redirect`,
|
||||
// TODO: replace it with your own backend to secure client_secret:
|
||||
tokenEndpoint: `https://oauth.yandex.ru/token?grant_type=authorization_code&client_id=${YANDEX_OAUTH_CLIENT}&client_secret=${YANDEX_OAUTH_SECRET}`,
|
||||
},
|
||||
clientId: YANDEX_OAUTH_CLIENT,
|
||||
redirectUrl: `${APP_ID}:/oauth2redirect`,
|
||||
scopes: ['login:info', 'login:avatar'],
|
||||
dangerouslyAllowInsecureHttpRequests: true,
|
||||
});
|
||||
|
||||
callback(authState.accessToken);
|
||||
```
|
||||
|
||||
## Apple ID login
|
||||
|
||||
[react-native-apple-authentication](https://github.com/invertase/react-native-apple-authentication) has its own [documentation](https://github.com/invertase/react-native-apple-authentication/tree/main/docs) on setting up OAuth using Apple ID.
|
|
@ -0,0 +1,60 @@
|
|||
Sometimes you need to keep scroll position of `FlatList` in React Native after some user interactions.
|
||||
|
||||
```typescript
|
||||
// interact() is doing some stuff, that changes FlatList scroll size
|
||||
type Props = { interact: () => void; }
|
||||
|
||||
const SomeList: FC<Props> = ({ interact }) => {
|
||||
const scrollPosition = useRef(0);
|
||||
const scrollHeight = useRef(0);
|
||||
|
||||
// set it to `true` before interaction and back to `false` right after
|
||||
const shouldKeepScrollPosition = useRef(false);
|
||||
|
||||
const onScroll = useCallback(
|
||||
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
||||
scrollPosition.current = event.nativeEvent.contentOffset.y;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const onContentSizeChange = useCallback((_: number, h: number) => {
|
||||
if (!shouldKeepScrollPosition.current) {
|
||||
scrollHeight.current = h;
|
||||
return;
|
||||
}
|
||||
|
||||
ref.current?.scrollToOffset({
|
||||
offset: scrollPosition.current + (h - scrollHeight.current),
|
||||
animated: false,
|
||||
});
|
||||
|
||||
scrollHeight.current = h;
|
||||
}, []);
|
||||
|
||||
// onInteraction wraps interaction to preserve scroll position
|
||||
const onInteraction = useCallback(
|
||||
() => {
|
||||
shouldKeepScrollPosition.current = true;
|
||||
|
||||
setTimeout(() => {
|
||||
interact();
|
||||
}, 0);
|
||||
|
||||
setTimeout(() => {
|
||||
shouldKeepScrollPosition.current = false;
|
||||
}, 500);
|
||||
},
|
||||
[setSelectedSubThemes],
|
||||
);
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
// ...required FlatList options
|
||||
ref={ref}
|
||||
onContentSizeChange={onContentSizeChange}
|
||||
onRefresh={onRefresh}
|
||||
onScroll={onScroll}
|
||||
/>
|
||||
)
|
||||
}
|
65
content/Frontend/React Native/Useful comands.md
Normal file
65
content/Frontend/React Native/Useful comands.md
Normal file
|
@ -0,0 +1,65 @@
|
|||
## Show android logcat
|
||||
|
||||
```shell
|
||||
adb logcat com.application:I "*:S"
|
||||
```
|
||||
|
||||
## Get .apk's SHA-256
|
||||
|
||||
```bash
|
||||
keytool -printcert -jarfile "$1"
|
||||
```
|
||||
|
||||
## Assemble debug release on Android
|
||||
|
||||
Packages release with bundled resources.
|
||||
|
||||
```shell
|
||||
npx react-native bundle \
|
||||
--platform android \
|
||||
--dev false \
|
||||
--entry-file index.js \
|
||||
--bundle-output android/app/src/main/assets/index.android.bundle \
|
||||
--assets-dest android/app/src/main/res/
|
||||
|
||||
cd android && ./gradlew assembleDebug
|
||||
|
||||
# do your stuff
|
||||
|
||||
./gradlew clean
|
||||
```
|
||||
|
||||
## Send release to Android device
|
||||
|
||||
```shell
|
||||
cd ./android \
|
||||
&& ./gradlew assembleRelease \
|
||||
&& adb install ./app/build/outputs/apk/release/app-release.apk
|
||||
```
|
||||
|
||||
## Deep links
|
||||
|
||||
- https://zarah.dev/2022/02/08/android12-deeplinks.html
|
||||
- https://developer.android.com/training/app-links/verify-site-associations#invoke-domain-verification
|
||||
- https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://miin.ru&relation=delegate_permission/common.handle_all_urls
|
||||
|
||||
### Open deep links
|
||||
|
||||
```shell
|
||||
# ios
|
||||
xcrun simctl openurl booted $1
|
||||
|
||||
# android
|
||||
adb shell am start -W -a android.intent.action.VIEW -d $1 \
|
||||
com.application
|
||||
```
|
||||
|
||||
### Reverify links on Android
|
||||
|
||||
```shell
|
||||
PACKAGE="com.application"
|
||||
|
||||
adb shell pm set-app-links --package $PACKAGE 0 all && \
|
||||
adb shell pm verify-app-links --re-verify $PACKAGE
|
||||
```
|
||||
|
106
content/Frontend/React/Axios refresh token on React.md
Normal file
106
content/Frontend/React/Axios refresh token on React.md
Normal file
|
@ -0,0 +1,106 @@
|
|||
`<ApiProvider />` component, that will handle token refresh if needed. Refresh function should, probably, be passed through component props.
|
||||
|
||||
```typescript
|
||||
import axios from "axios";
|
||||
import React, {
|
||||
createContext,
|
||||
FC,
|
||||
PropsWithChildren,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
} from "react";
|
||||
|
||||
interface APIProviderProps extends PropsWithChildren {
|
||||
tokens: {
|
||||
access: string;
|
||||
refresh: string;
|
||||
};
|
||||
logout: () => void;
|
||||
}
|
||||
|
||||
const APIContext = createContext({
|
||||
client: axios.create({
|
||||
baseURL: process.env.NEXT_PUBLIC_API_ENDPOINT,
|
||||
}),
|
||||
});
|
||||
|
||||
const APIProvider: FC<APIProviderProps> = ({
|
||||
tokens,
|
||||
logout,
|
||||
children,
|
||||
}) => {
|
||||
const client = useRef(
|
||||
axios.create({
|
||||
baseURL: process.env.NEXT_PUBLIC_API_ENDPOINT,
|
||||
})
|
||||
).current;
|
||||
|
||||
const refreshTokens = useCallback<() => string>(() => {
|
||||
// TODO: implement me
|
||||
throw new Error("not implemented");
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!tokens.access) {
|
||||
return;
|
||||
}
|
||||
|
||||
// append `access` token to all requests
|
||||
const req = client.interceptors.request.use(
|
||||
async (config) => {
|
||||
config.headers = {
|
||||
Authorization: `Bearer ${tokens.access}`,
|
||||
};
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// refreshing interceptor
|
||||
const resp = client.interceptors.response.use(
|
||||
(response) => {
|
||||
return response;
|
||||
},
|
||||
async function (error) {
|
||||
const originalRequest = error.config;
|
||||
|
||||
if (error.response.status === 401 && !originalRequest._retry) {
|
||||
originalRequest._retry = true;
|
||||
|
||||
const newToken = refreshTokens;
|
||||
|
||||
return axios({
|
||||
...originalRequest,
|
||||
headers: {
|
||||
...originalRequest.headers,
|
||||
Authorization: "Bearer " + newToken,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
logout();
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
axios.interceptors.request.eject(req);
|
||||
axios.interceptors.request.eject(resp);
|
||||
};
|
||||
}, [client, tokens.access, tokens.refresh, refreshTokens, logout]);
|
||||
|
||||
return (
|
||||
<APIContext.Provider value={{ client }}>
|
||||
{children}
|
||||
</APIContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAPI = () => useContext(APIContext).client;
|
||||
|
||||
export { APIProvider };
|
||||
```
|
32
content/Frontend/React/Axios with AbortController.md
Normal file
32
content/Frontend/React/Axios with AbortController.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
If you need to cancel some request, use [axios with AbortController](https://axios-http.com/docs/cancellation). Previously axios used cancellation token, but now it's deprecated.
|
||||
|
||||
`AbortController` can be used with a multiple requests to cancel them at once.
|
||||
|
||||
```typescript
|
||||
import { useCallback, useRef } from "react";
|
||||
import axios from 'axios';
|
||||
|
||||
const client = axios.create();
|
||||
|
||||
export const useGetUsers = () => {
|
||||
const controller = useRef(new AbortController());
|
||||
|
||||
const get = useCallback(async () => {
|
||||
const result = await client.get("/", {
|
||||
// params and props here
|
||||
signal: controller.current.signal,
|
||||
});
|
||||
|
||||
return result.data;
|
||||
}, []);
|
||||
|
||||
const cancel = useCallback(() => {
|
||||
controller.current.abort();
|
||||
|
||||
// controller should be rewritten or all requests will fail
|
||||
controller.current = new AbortController();
|
||||
}, [controller]);
|
||||
|
||||
return { get, cancel };
|
||||
};
|
||||
```
|
|
@ -0,0 +1,17 @@
|
|||
The topic's fully covered in the [official documentation](https://vuejs.org/guide/typescript/options-api.html#augmenting-global-properties) and in [Add global variable to window](Add%20global%20variable%20to%20window.md).
|
||||
|
||||
For example, you want to add global `$http` and `$translate` services to all of project's components:
|
||||
|
||||
```typescript
|
||||
// ~/index.d.ts or ~/custom.d.ts
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
declare module 'vue' {
|
||||
interface ComponentCustomProperties {
|
||||
$http: typeof axios
|
||||
$translate: (key: string) => string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
16
content/Frontend/Vue/Make Nuxt handle Obsidian highlights.md
Normal file
16
content/Frontend/Vue/Make Nuxt handle Obsidian highlights.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
By default [Nuxt Content Plugin](https://content.nuxtjs.org) not handling `==highlight==` links. To fix that we will create `Nitro` plugin:
|
||||
|
||||
```typescript
|
||||
// ~/server/plugins/highlight.ts
|
||||
export default defineNitroPlugin((nitroApp) => {
|
||||
nitroApp.hooks.hook("content:file:beforeParse", (file) => {
|
||||
if (file._id.endsWith(".md")) {
|
||||
file.body = file.body.replace(
|
||||
/==([^=]+)==/gs,
|
||||
`<span class="highlight">$1</span>`
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue