Fix permalink to not joined channels and to not fetched posts. (#6294)

* Fix permalink to not joined channels and to not fetched posts.

* i18n-extract

* Implement as designed

* Revert unintended change

* Minor fix and fix svgs

* updated svg to fix masking problems and colors

* Fix lint

* Address feedback

* Update join_public_channel.tsx

fixed public channel svg

* Update join_public_channel.tsx

* Update join_private_channel.tsx

* Address feedback

Co-authored-by: Matthew Birtch <mattbirtch@gmail.com>
This commit is contained in:
Daniel Espino García 2022-06-17 19:23:12 +02:00 committed by GitHub
parent 1ca401ef3c
commit ee3b655991
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 750 additions and 89 deletions

View file

@ -1,11 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fetchMyChannelsForTeam} from '@actions/remote/channel';
import DatabaseManager from '@database/manager';
import {getCommonSystemValues} from '@queries/servers/system';
import {getTeamById, getTeamByName} from '@queries/servers/team';
import {permalinkBadTeam} from '@utils/draft';
import {getCurrentTeam} from '@queries/servers/team';
import {displayPermalink} from '@utils/permalink';
import {PERMALINK_GENERIC_TEAM_NAME_REDIRECT} from '@utils/url';
@ -21,30 +18,14 @@ export const showPermalink = async (serverUrl: string, teamName: string, postId:
try {
let name = teamName;
let team: TeamModel | undefined;
const system = await getCommonSystemValues(database);
if (!name || name === PERMALINK_GENERIC_TEAM_NAME_REDIRECT) {
team = await getTeamById(database, system.currentTeamId);
team = await getCurrentTeam(database);
if (team) {
name = team.name;
}
}
if (!team) {
team = await getTeamByName(database, name);
if (!team) {
permalinkBadTeam(intl);
return {error: 'Bad Permalink team'};
}
}
if (team.id !== system.currentTeamId) {
const result = await fetchMyChannelsForTeam(serverUrl, team.id, true, 0, false, true);
if (result.error) {
return {error: result.error};
}
}
await displayPermalink(team.name, postId, openAsPermalink);
await displayPermalink(name, postId, openAsPermalink);
return {error: undefined};
} catch (error) {

View file

@ -0,0 +1,149 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as React from 'react';
import Svg, {
Path,
Mask,
G,
EMaskUnits,
} from 'react-native-svg';
type Props = {
theme: Theme;
}
function SvgComponent({theme}: Props) {
return (
<Svg
width={200}
height={201}
fill='none'
viewBox='0 0 210 170'
>
<Path
d='M20.215 68.747h41.93a5.84 5.84 0 0 1 4.143 1.704 5.864 5.864 0 0 1 1.727 4.14v26.71a5.879 5.879 0 0 1-1.727 4.141 5.842 5.842 0 0 1-4.144 1.704h-6.188v9.998l-9.281-9.998H20.23a5.857 5.857 0 0 1-4.143-1.704 5.871 5.871 0 0 1-1.728-4.141v-26.71a5.871 5.871 0 0 1 1.722-4.135 5.844 5.844 0 0 1 4.134-1.709Z'
fill={theme.buttonBg}
/>
<Path
d='M46.675 107.146H20.23a5.857 5.857 0 0 1-4.143-1.704 5.871 5.871 0 0 1-1.728-4.141V85.086s1.846 14.994 2.178 16.314c.332 1.32.99 3.295 4.109 3.622 3.119.328 26.029 2.124 26.029 2.124Z'
fill='#000'
fillOpacity={0.16}
/>
<Path
d='M55.501 84.128a3.77 3.77 0 0 0-3.49 2.337 3.795 3.795 0 0 0 .82 4.126 3.774 3.774 0 0 0 6.447-2.677 3.787 3.787 0 0 0-2.33-3.499 3.764 3.764 0 0 0-1.447-.287ZM41.18 84.128a3.77 3.77 0 0 0-3.49 2.337 3.794 3.794 0 0 0 .819 4.126 3.775 3.775 0 0 0 4.116.82 3.78 3.78 0 0 0 2.331-3.497 3.79 3.79 0 0 0-1.104-2.678 3.772 3.772 0 0 0-2.673-1.108ZM26.873 84.128a3.77 3.77 0 0 0-3.493 2.334 3.793 3.793 0 0 0 .816 4.127 3.774 3.774 0 0 0 6.45-2.675 3.787 3.787 0 0 0-2.328-3.498 3.764 3.764 0 0 0-1.445-.288Z'
fill={theme.centerChannelBg}
/>
<Path
d='M63.664 79.93a11.918 11.918 0 0 0-5.668-7.174.411.411 0 0 1 .168-.779c2.644-.159 7.98.407 6.307 7.914a.417.417 0 0 1-.807.04Z'
fill='#fff'
fillOpacity={0.16}
/>
<Path
fillRule='evenodd'
clipRule='evenodd'
d='M207.944 110.447c0 36.185-29.205 65.518-65.232 65.518-36.026 0-65.231-29.333-65.231-65.518 0-36.184 29.205-65.518 65.231-65.518 36.027 0 65.232 29.334 65.232 65.518Zm-.637 0c0 35.832-28.92 64.879-64.595 64.879-35.674 0-64.595-29.047-64.595-64.879 0-35.832 28.921-64.879 64.595-64.879 35.675 0 64.595 29.047 64.595 64.879Z'
fill={theme.centerChannelColor}
fillOpacity={0.16}
/>
<Path
d='M142.712 175.326c35.675 0 64.595-29.047 64.595-64.879 0-35.832-28.92-64.879-64.595-64.879s-64.595 29.047-64.595 64.879c0 35.832 28.92 64.879 64.595 64.879Z'
fill={theme.centerChannelBg}
/>
<Path
d='M142.712 175.326c35.675 0 64.595-29.047 64.595-64.879 0-35.832-28.92-64.879-64.595-64.879s-64.595 29.047-64.595 64.879c0 35.832 28.92 64.879 64.595 64.879Z'
fill={theme.centerChannelColor}
fillOpacity={0.16}
/>
<Path
d='M155.792 71.637c2.437-.51 6.786-.958 9.91.984 2.029 1.263 3.191 3.507 4.631 5.416 1.631 2.156 3.689 3.97 5.408 6.063 5.246 6.395 6.965 15.552 4.378 23.427-.823 2.499-2.039 4.863-2.694 7.409-.83 3.229-.716 6.611-.976 9.933-.694 9.229-4.142 17.993-7.549 26.587-1.023 2.58-2.087 5.226-3.98 7.248-3.074 3.282-8.243 4.369-12.369 2.604-2.995-1.284-5.377-3.873-8.52-4.731-1.497-.407-3.073-.393-4.618-.532-7.869-.718-15.183-5.787-18.628-12.915-3.446-7.128-2.891-16.048 1.411-22.69 1.431-2.213 3.234-4.16 5.008-6.093l9.082-9.821c2.301-2.486 4.677-5.104 5.602-8.371.679-2.395.515-4.946.715-7.425.384-4.678 2.194-9.342 5.539-12.614 3.346-3.272 5.487-4.026 7.65-4.479Z'
fill='#6F370B'
/>
<Mask
id='a'
maskUnits={'userSpaceOnUse' as EMaskUnits.USER_SPACE_ON_USE}
x={76}
y={43}
width={134}
height={135}
>
<Path
d='M142.712 176.326c36.231 0 65.595-29.499 65.595-65.879 0-36.38-29.364-65.879-65.595-65.879-36.231 0-65.595 29.5-65.595 65.879 0 36.38 29.364 65.879 65.595 65.879Z'
fill='#FFFFFF'
/>
</Mask>
<G mask='url(#a)'>
<Path
d='m156.679 118.534-8.794 18.965c-.238.515-.029 1.677.477 1.916 8.155 3.722 11.617 7.744 12.977 9.222a511.194 511.194 0 0 1 17.795 20.405c4.462-2.218 14.091-9.73 19.337-16.915 20.583-28.192 10.237-52.42 7.63-51.498-11.684 4.137-16.732 6.977-26.707 14.372-2.191 1.626-6.168 3.667-8.703 4.67-4.242 1.677-10.163-.797-12.471-1.916-.518-.266-1.338.232-1.541.779Z'
fill={theme.centerChannelBg}
/>
<Path
d='m156.679 118.534-8.794 18.965c-.239.515-.029 1.677.477 1.916 8.155 3.722 11.617 7.744 12.976 9.222a510.414 510.414 0 0 1 17.796 20.405c4.462-2.218 14.09-9.73 19.336-16.915 20.584-28.192 10.237-52.42 7.631-51.498-11.684 4.137-16.732 6.977-26.707 14.372-2.191 1.626-6.169 3.667-8.703 4.67-4.243 1.677-10.163-.797-12.472-1.916-.517-.266-1.337.232-1.54.779Z'
fill={theme.centerChannelColor}
fillOpacity={0.04}
/>
</G>
<Path
d='M88.124 49.27c.121 1.962-.046 8.863 0 9.51.503 8.58 19.505 32.628 21.348 34.443 4.44 4.374 13.955 10.01 19.315 13.174 11.148 6.577 15.831 7.162 27.899 12.137l-8.794 18.965c-18.278-6.599-26.266-11.449-35.804-17.916-3.369-2.285-10.144-7.076-12.876-9.821-11.208-11.257-16.103-32.335-20.746-42.395-2.265-4.91-3.538-5.16-5.007-7.186-1.908-2.635-2.027-3.473-3.577-5.749-2.53-3.715-7.48-6.64-9.062-9.87a.413.413 0 0 1 .303-.584.409.409 0 0 1 .246.035c2.974 1.459 5.177 2.994 8.396 4.551.544-1.406-1.192-4.072-2.862-6.707-1.561-2.467-4.65-10.898-3.457-12.096.589-.591 2.385 1.97 3.219 3.473 3.1 5.51 4.65 7.066 4.65 7.066s-6.372-11.286-5.962-12.215c.954-2.156 5.228 4.04 8.585 9.102 1.907 2.874 3.1 3.592 3.1 3.592s-1.073-8.742-1.789-12.814c-.524-2.987 1.26-2.256 2.504 1.078.716 1.916 1.05 3.399 2.146 6.706a45.414 45.414 0 0 0 1.908 4.79c1.123 2.506 1.907 3.354 2.742 4.672.253-2.35.358-3.234 1.43-5.51 1.136-2.395 3.816-5.508 2.624-.718-.873 3.473-.594 8.462-.48 10.288ZM168.43 109.482c-1.028-.558-2.291-1.152-3.338-1.677-2.17-1.087-4.037-2.079-5.63-3.916a63.152 63.152 0 0 1-8.675-12.951c-1.023-2.031-1.946-4.154-2.251-6.41-.305-2.256.069-4.683 1.431-6.498 2.384-3.178 7.945-4.103 10.589-3.28 2.948.918 6.815 4.823 9.3 8.145 3.577 4.776 5.723 8.297 8.346 13.653.238.479 1.206 4.852 1.321 5.065 2.971 5.474 6.786 7.39 6.786 7.39l2.442-.958a6.171 6.171 0 0 1 3.494-.309 6.191 6.191 0 0 1 3.102 1.645 7.433 7.433 0 0 1 1.335 1.651c2.862 5.509 2.888 11.736-.954 15.569-3.841 3.832-7.656 5.37-12.995 4.431-2.781-.479-5.723-1.677-8.449-3.248-3.701-2.156-3.963-7.092-.715-9.873.019.007-2.394-6.951-5.139-8.429Z'
fill='#FFBC1F'
/>
<Path
d='M171.203 112.682c5.392-2.506 6.796-5.691 7.123-6.661a.443.443 0 0 0-.119-.463l-.015-.012a.434.434 0 0 0-.368-.109.436.436 0 0 0-.271.157 9.81 9.81 0 0 1-2.351 2.058 9.203 9.203 0 0 1-5.287 1.756 8.988 8.988 0 0 1-2.079-.24c.208.108.415.216.608.321.985.534 1.939 1.801 2.759 3.193Z'
fill='#CC8F00'
/>
<Path
d='M166.399 99.609a6.721 6.721 0 0 0 3.851-3.26c.214-.407-.403-.772-.618-.362a6 6 0 0 1-3.429 2.942c-.434.146-.238.84.191.692l.005-.012ZM157.373 79.984c-1.257 4.908-1.478 9.998-6.247 12.873-3.367-2.499-4.905-10.484-2.623-14.633 1.33-2.41 5.67-5.202 9.023-6.268 1.094-.348 5.808 2.251 5.761 2.675-.353 3.236-3.842 6.297-5.485 9.102l-.429-3.749Z'
fill='#6F370B'
/>
<Path
d='M174.17 90.298c-.208-1.109.839-2.076.93-3.202.117-1.452-1.317-2.493-2.576-3.22a.844.844 0 0 0-.543-.162c-.315.055-.456.424-.511.74a5.848 5.848 0 0 0 .878 4.184l1.822 1.66Z'
fill='#FFBC1F'
/>
<Path
d='M173.297 86.708a.683.683 0 0 1 .217-.853c.381-.256.024-.879-.36-.62a1.422 1.422 0 0 0-.477 1.837c.207.412.825.048.617-.364h.003ZM83.943 44.688c-1.771 1.823-2.68 4.508-3.004 6.994-.239 1.917.513 4.537 2.244 5.596.393.24.753-.381.36-.62-1.75-1.071-2.146-3.692-1.796-5.529.396-2.127 1.173-4.362 2.702-5.933.322-.33-.181-.838-.506-.508ZM75.373 63.565c1.639 1.164 4.343 1.368 5.876-.139.329-.323-.176-.83-.506-.508-1.318 1.296-3.631 1.004-5.007.027-.377-.269-.735.354-.36.62h-.003ZM162.35 91.544c.488.82.853 1.708 1.082 2.635.122.5.122 1.025.239 1.52.005.17.052.334.136.48.617.795 1.819-.213 2.212-.748.272-.373-.348-.733-.617-.364-.165.226-.592.736-.882.614-.201-.084-.148-.192-.179-.48a9.881 9.881 0 0 0-1.369-4.019.356.356 0 0 0-.646.094.36.36 0 0 0 .028.268h-.004ZM164.615 85.71c-1.073 0-1.076 1.676 0 1.676 1.075 0 1.078-1.677 0-1.677ZM157.759 90.44c-1.073 0-1.075 1.676 0 1.676 1.076 0 1.078-1.676 0-1.676Z'
fill='#6F370B'
/>
<Path
d='M35.265 117.963H11.052a3.359 3.359 0 0 0-2.392.983 3.39 3.39 0 0 0-.998 2.392v15.423a3.39 3.39 0 0 0 2.097 3.122c.41.169.85.255 1.293.253h3.574v5.774l5.36-5.774h15.27a3.359 3.359 0 0 0 2.393-.983 3.39 3.39 0 0 0 .998-2.392v-15.423a3.392 3.392 0 0 0-.995-2.389 3.376 3.376 0 0 0-2.387-.986Z'
fill='#FFBC1F'
/>
<Path
d='M19.986 140.136h15.27a3.359 3.359 0 0 0 2.393-.983 3.39 3.39 0 0 0 .998-2.392v-9.363s-1.066 8.658-1.258 9.421c-.192.762-.572 1.902-2.373 2.091-1.8.189-15.03 1.226-15.03 1.226Z'
fill='#CC8F00'
/>
<Path
d='M14.889 126.845a2.179 2.179 0 0 1 2.015 1.349 2.191 2.191 0 0 1-.473 2.383 2.182 2.182 0 0 1-2.377.474 2.184 2.184 0 0 1-1.347-2.02 2.186 2.186 0 0 1 1.346-2.021c.265-.109.55-.166.836-.165ZM23.159 126.845a2.179 2.179 0 0 1 2.015 1.349 2.191 2.191 0 0 1-.473 2.383 2.182 2.182 0 0 1-2.377.474 2.184 2.184 0 0 1-1.346-2.02 2.188 2.188 0 0 1 1.346-2.021c.265-.109.548-.166.835-.165ZM31.42 126.845a2.187 2.187 0 0 1 .43 4.33 2.185 2.185 0 0 1-1.971-3.69 2.18 2.18 0 0 1 1.541-.64Z'
fill={theme.centerChannelBg}
/>
<Path
d='M10.175 124.421a6.86 6.86 0 0 1 3.273-4.143.24.24 0 0 0 .046-.395.24.24 0 0 0-.143-.055c-1.527-.092-4.608.235-3.642 4.57a.24.24 0 0 0 .224.195.245.245 0 0 0 .15-.044.247.247 0 0 0 .092-.128Z'
fill='#FFD470'
/>
<Path
d='M54.952 138.309v32.874c0 2.453 1.759 4.498 3.87 4.498h46.357c2.11 0 3.869-2.045 3.869-4.498v-32.874H54.952Z'
fill='#FFBC1F'
/>
<Path
d='M109.048 133.764c0-2.479-1.761-4.545-3.874-4.545H58.826c-2.113 0-3.874 2.066-3.874 4.545v4.545h54.096v-4.545Z'
fill='#CC8F00'
/>
<Path
d='M66.737 130.716c3.453 0 6.247 1.147 6.247 2.621 0 1.475-2.794 2.621-6.246 2.621-3.453 0-6.247-1.146-6.247-2.621 0-1.392 2.794-2.621 6.246-2.621ZM97.26 130.716c3.452 0 6.246 1.147 6.246 2.621 0 1.475-2.794 2.621-6.246 2.621-3.452 0-6.247-1.146-6.247-2.621 0-1.392 2.795-2.621 6.247-2.621Z'
fill='#090A0B'
/>
<Path
d='M82.031 114.404c-10.43 0-18.965 8.523-18.965 19.002 0 .631 1.343 1.212 3.114 1.212v-1.144c.632-8.838 7.444-15.913 15.851-15.913 8.408 0 15.22 7.007 15.79 15.908v1.149c1.77 0 3.112-.518 3.112-1.149.063-10.542-8.47-19.065-18.902-19.065Z'
fill='#DDDFE4'
/>
<Path
d='M97.89 133.456c0-9.136-7.566-16.022-15.953-16.022s-16.14 6.886-15.757 17.184c1.765 0 3.334-.523 3.334-1.162 0-5.808 4.793-12.702 12.486-12.702 7.693 0 12.485 6.894 12.485 12.702 0 .639 1.577 1.162 3.406 1.162v-1.162Z'
fill='#BABEC9'
/>
<Path
d='m86.807 167.823-1.972-12.86c1.15-.901 1.972-2.294 1.972-3.85 0-2.622-2.137-4.833-4.767-4.833-2.63 0-4.767 2.129-4.767 4.833 0 1.556.74 3.031 1.973 3.85l-1.973 12.86h9.534Z'
fill='#090A0B'
/>
</Svg>
);
}
export default SvgComponent;

View file

@ -0,0 +1,125 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as React from 'react';
import Svg, {
Path,
Mask,
G,
EMaskUnits,
} from 'react-native-svg';
type Props = {
theme: Theme;
}
function SvgComponent({theme}: Props) {
return (
<Svg
width={200}
height={201}
fill='none'
viewBox='0 0 210 170'
>
<Path
d='M20.215 68.747h41.93a5.84 5.84 0 0 1 4.143 1.704 5.864 5.864 0 0 1 1.727 4.14v26.71a5.879 5.879 0 0 1-1.727 4.141 5.842 5.842 0 0 1-4.144 1.704h-6.188v9.998l-9.281-9.998H20.23a5.857 5.857 0 0 1-4.143-1.704 5.871 5.871 0 0 1-1.728-4.141v-26.71a5.871 5.871 0 0 1 1.722-4.135 5.844 5.844 0 0 1 4.134-1.709Z'
fill={theme.buttonBg}
/>
<Path
d='M46.675 107.146H20.23a5.857 5.857 0 0 1-4.143-1.704 5.871 5.871 0 0 1-1.728-4.141V85.086s1.846 14.994 2.178 16.314c.332 1.32.99 3.295 4.109 3.622 3.119.328 26.029 2.124 26.029 2.124Z'
fill='#000'
fillOpacity={0.16}
/>
<Path
d='M55.501 84.128a3.77 3.77 0 0 0-3.49 2.337 3.795 3.795 0 0 0 .82 4.126 3.774 3.774 0 0 0 6.447-2.677 3.787 3.787 0 0 0-2.33-3.499 3.764 3.764 0 0 0-1.447-.287ZM41.18 84.128a3.77 3.77 0 0 0-3.49 2.337 3.794 3.794 0 0 0 .819 4.126 3.775 3.775 0 0 0 4.116.82 3.78 3.78 0 0 0 2.331-3.497 3.79 3.79 0 0 0-1.104-2.678 3.772 3.772 0 0 0-2.673-1.108ZM26.873 84.128a3.77 3.77 0 0 0-3.493 2.334 3.793 3.793 0 0 0 .816 4.127 3.774 3.774 0 0 0 6.45-2.675 3.787 3.787 0 0 0-2.328-3.498 3.764 3.764 0 0 0-1.445-.288Z'
fill={theme.centerChannelBg}
/>
<Path
d='M63.664 79.93a11.918 11.918 0 0 0-5.668-7.174.411.411 0 0 1 .168-.779c2.644-.159 7.98.407 6.307 7.914a.417.417 0 0 1-.807.04Z'
fill='#fff'
fillOpacity={0.16}
/>
<Path
fillRule='evenodd'
clipRule='evenodd'
d='M207.944 110.447c0 36.185-29.205 65.518-65.232 65.518-36.026 0-65.231-29.333-65.231-65.518 0-36.184 29.205-65.518 65.231-65.518 36.027 0 65.232 29.334 65.232 65.518Zm-.637 0c0 35.832-28.92 64.879-64.595 64.879-35.674 0-64.595-29.047-64.595-64.879 0-35.832 28.921-64.879 64.595-64.879 35.675 0 64.595 29.047 64.595 64.879Z'
fill={theme.centerChannelColor}
fillOpacity={0.16}
/>
<Path
d='M142.712 175.326c35.675 0 64.595-29.047 64.595-64.879 0-35.832-28.92-64.879-64.595-64.879s-64.595 29.047-64.595 64.879c0 35.832 28.92 64.879 64.595 64.879Z'
fill={theme.centerChannelBg}
/>
<Path
d='M142.712 175.326c35.675 0 64.595-29.047 64.595-64.879 0-35.832-28.92-64.879-64.595-64.879s-64.595 29.047-64.595 64.879c0 35.832 28.92 64.879 64.595 64.879Z'
fill={theme.centerChannelColor}
fillOpacity={0.16}
/>
<Path
d='M155.792 71.637c2.437-.51 6.786-.958 9.91.984 2.029 1.263 3.191 3.507 4.631 5.416 1.631 2.156 3.689 3.97 5.408 6.063 5.246 6.395 6.965 15.552 4.378 23.427-.823 2.499-2.039 4.863-2.694 7.409-.83 3.229-.716 6.611-.976 9.933-.694 9.229-4.142 17.993-7.549 26.587-1.023 2.58-2.087 5.226-3.98 7.248-3.074 3.282-8.243 4.369-12.369 2.604-2.995-1.284-5.377-3.873-8.52-4.731-1.497-.407-3.073-.393-4.618-.532-7.869-.718-15.183-5.787-18.628-12.915-3.446-7.128-2.891-16.048 1.411-22.69 1.431-2.213 3.234-4.16 5.008-6.093l9.082-9.821c2.301-2.486 4.677-5.104 5.602-8.371.679-2.395.515-4.946.715-7.425.384-4.678 2.194-9.342 5.539-12.614 3.346-3.272 5.487-4.026 7.65-4.479Z'
fill='#6F370B'
/>
<Mask
id='a'
maskUnits={'userSpaceOnUse' as EMaskUnits.USER_SPACE_ON_USE}
x={76}
y={43}
width={134}
height={135}
>
<Path
d='M142.712 176.326c36.231 0 65.595-29.499 65.595-65.879 0-36.38-29.364-65.879-65.595-65.879-36.231 0-65.595 29.5-65.595 65.879 0 36.38 29.364 65.879 65.595 65.879Z'
fill='#FFFFFF'
/>
</Mask>
<G mask='url(#a)'>
<Path
d='m156.679 118.534-8.794 18.965c-.238.515-.029 1.677.477 1.916 8.155 3.722 11.617 7.744 12.977 9.222a511.194 511.194 0 0 1 17.795 20.405c4.462-2.218 14.091-9.73 19.337-16.915 20.583-28.192 10.237-52.42 7.63-51.498-11.684 4.137-16.732 6.977-26.707 14.372-2.191 1.626-6.168 3.667-8.703 4.67-4.242 1.677-10.163-.797-12.471-1.916-.518-.266-1.338.232-1.541.779Z'
fill={theme.centerChannelBg}
/>
<Path
d='m156.679 118.534-8.794 18.965c-.239.515-.029 1.677.477 1.916 8.155 3.722 11.617 7.744 12.976 9.222a510.414 510.414 0 0 1 17.796 20.405c4.462-2.218 14.09-9.73 19.336-16.915 20.584-28.192 10.237-52.42 7.631-51.498-11.684 4.137-16.732 6.977-26.707 14.372-2.191 1.626-6.169 3.667-8.703 4.67-4.243 1.677-10.163-.797-12.472-1.916-.517-.266-1.337.232-1.54.779Z'
fill={theme.centerChannelColor}
fillOpacity={0.04}
/>
</G>
<Path
d='M88.124 49.27c.121 1.962-.046 8.863 0 9.51.503 8.58 19.505 32.628 21.348 34.443 4.44 4.374 13.955 10.01 19.315 13.174 11.148 6.577 15.831 7.162 27.899 12.137l-8.794 18.965c-18.278-6.599-26.266-11.449-35.804-17.916-3.369-2.285-10.144-7.076-12.876-9.821-11.208-11.257-16.103-32.335-20.746-42.395-2.265-4.91-3.538-5.16-5.007-7.186-1.908-2.635-2.027-3.473-3.577-5.749-2.53-3.715-7.48-6.64-9.062-9.87a.413.413 0 0 1 .303-.584.409.409 0 0 1 .246.035c2.974 1.459 5.177 2.994 8.396 4.551.544-1.406-1.192-4.072-2.862-6.707-1.561-2.467-4.65-10.898-3.457-12.096.589-.591 2.385 1.97 3.219 3.473 3.1 5.51 4.65 7.066 4.65 7.066s-6.372-11.286-5.962-12.215c.954-2.156 5.228 4.04 8.585 9.102 1.907 2.874 3.1 3.592 3.1 3.592s-1.073-8.742-1.789-12.814c-.524-2.987 1.26-2.256 2.504 1.078.716 1.916 1.05 3.399 2.146 6.706a45.414 45.414 0 0 0 1.908 4.79c1.123 2.506 1.907 3.354 2.742 4.672.253-2.35.358-3.234 1.43-5.51 1.136-2.395 3.816-5.508 2.624-.718-.873 3.473-.594 8.462-.48 10.288ZM168.43 109.482c-1.028-.558-2.291-1.152-3.338-1.677-2.17-1.087-4.037-2.079-5.63-3.916a63.152 63.152 0 0 1-8.675-12.951c-1.023-2.031-1.946-4.154-2.251-6.41-.305-2.256.069-4.683 1.431-6.498 2.384-3.178 7.945-4.103 10.589-3.28 2.948.918 6.815 4.823 9.3 8.145 3.577 4.776 5.723 8.297 8.346 13.653.238.479 1.206 4.852 1.321 5.065 2.971 5.474 6.786 7.39 6.786 7.39l2.442-.958a6.171 6.171 0 0 1 3.494-.309 6.191 6.191 0 0 1 3.102 1.645 7.433 7.433 0 0 1 1.335 1.651c2.862 5.509 2.888 11.736-.954 15.569-3.841 3.832-7.656 5.37-12.995 4.431-2.781-.479-5.723-1.677-8.449-3.248-3.701-2.156-3.963-7.092-.715-9.873.019.007-2.394-6.951-5.139-8.429Z'
fill='#FFBC1F'
/>
<Path
d='M171.203 112.682c5.392-2.506 6.796-5.691 7.123-6.661a.443.443 0 0 0-.119-.463l-.015-.012a.434.434 0 0 0-.368-.109.436.436 0 0 0-.271.157 9.81 9.81 0 0 1-2.351 2.058 9.203 9.203 0 0 1-5.287 1.756 8.988 8.988 0 0 1-2.079-.24c.208.108.415.216.608.321.985.534 1.939 1.801 2.759 3.193Z'
fill='#CC8F00'
/>
<Path
d='M166.399 99.609a6.721 6.721 0 0 0 3.851-3.26c.214-.407-.403-.772-.618-.362a6 6 0 0 1-3.429 2.942c-.434.146-.238.84.191.692l.005-.012ZM157.373 79.984c-1.257 4.908-1.478 9.998-6.247 12.873-3.367-2.499-4.905-10.484-2.623-14.633 1.33-2.41 5.67-5.202 9.023-6.268 1.094-.348 5.808 2.251 5.761 2.675-.353 3.236-3.842 6.297-5.485 9.102l-.429-3.749Z'
fill='#6F370B'
/>
<Path
d='M174.17 90.298c-.208-1.109.839-2.076.93-3.202.117-1.452-1.317-2.493-2.576-3.22a.844.844 0 0 0-.543-.162c-.315.055-.456.424-.511.74a5.848 5.848 0 0 0 .878 4.184l1.822 1.66Z'
fill='#FFBC1F'
/>
<Path
d='M173.297 86.708a.683.683 0 0 1 .217-.853c.381-.256.024-.879-.36-.62a1.422 1.422 0 0 0-.477 1.837c.207.412.825.048.617-.364h.003ZM83.943 44.688c-1.771 1.823-2.68 4.508-3.004 6.994-.239 1.917.513 4.537 2.244 5.596.393.24.753-.381.36-.62-1.75-1.071-2.146-3.692-1.796-5.529.396-2.127 1.173-4.362 2.702-5.933.322-.33-.181-.838-.506-.508ZM75.373 63.565c1.639 1.164 4.343 1.368 5.876-.139.329-.323-.176-.83-.506-.508-1.318 1.296-3.631 1.004-5.007.027-.377-.269-.735.354-.36.62h-.003ZM162.35 91.544c.488.82.853 1.708 1.082 2.635.122.5.122 1.025.239 1.52.005.17.052.334.136.48.617.795 1.819-.213 2.212-.748.272-.373-.348-.733-.617-.364-.165.226-.592.736-.882.614-.201-.084-.148-.192-.179-.48a9.881 9.881 0 0 0-1.369-4.019.356.356 0 0 0-.646.094.36.36 0 0 0 .028.268h-.004ZM164.615 85.71c-1.073 0-1.076 1.676 0 1.676 1.075 0 1.078-1.677 0-1.677ZM157.759 90.44c-1.073 0-1.075 1.676 0 1.676 1.076 0 1.078-1.676 0-1.676Z'
fill='#6F370B'
/>
<Path
d='M35.265 117.963H11.052a3.359 3.359 0 0 0-2.392.983 3.39 3.39 0 0 0-.998 2.392v15.423a3.39 3.39 0 0 0 2.097 3.122c.41.169.85.255 1.293.253h3.574v5.774l5.36-5.774h15.27a3.359 3.359 0 0 0 2.393-.983 3.39 3.39 0 0 0 .998-2.392v-15.423a3.392 3.392 0 0 0-.995-2.389 3.376 3.376 0 0 0-2.387-.986Z'
fill='#FFBC1F'
/>
<Path
d='M19.986 140.136h15.27a3.359 3.359 0 0 0 2.393-.983 3.39 3.39 0 0 0 .998-2.392v-9.363s-1.066 8.658-1.258 9.421c-.192.762-.572 1.902-2.373 2.091-1.8.189-15.03 1.226-15.03 1.226Z'
fill='#CC8F00'
/>
<Path
d='M14.889 126.845a2.179 2.179 0 0 1 2.015 1.349 2.191 2.191 0 0 1-.473 2.383 2.182 2.182 0 0 1-2.377.474 2.184 2.184 0 0 1-1.347-2.02 2.186 2.186 0 0 1 1.346-2.021c.265-.109.55-.166.836-.165ZM23.159 126.845a2.179 2.179 0 0 1 2.015 1.349 2.191 2.191 0 0 1-.473 2.383 2.182 2.182 0 0 1-2.377.474 2.184 2.184 0 0 1-1.346-2.02 2.188 2.188 0 0 1 1.346-2.021c.265-.109.548-.166.835-.165ZM31.42 126.845a2.187 2.187 0 0 1 .43 4.33 2.185 2.185 0 0 1-1.971-3.69 2.18 2.18 0 0 1 1.541-.64Z'
fill={theme.centerChannelBg}
/>
<Path
d='M10.175 124.421a6.86 6.86 0 0 1 3.273-4.143.24.24 0 0 0 .046-.395.24.24 0 0 0-.143-.055c-1.527-.092-4.608.235-3.642 4.57a.24.24 0 0 0 .224.195.245.245 0 0 0 .15-.044.247.247 0 0 0 .092-.128Z'
fill='#FFD470'
/>
</Svg>
);
}
export default SvgComponent;

View file

@ -0,0 +1,56 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as React from 'react';
import Svg, {Path, Ellipse} from 'react-native-svg';
type Props = {
theme: Theme;
}
function SvgComponent({theme}: Props) {
return (
<Svg
width={180}
height={157}
viewBox='0 0 180 157'
fill='none'
>
<Path
d='M127.838 40.436h-75.65a10.577 10.577 0 00-7.475 3.06 10.533 10.533 0 00-3.117 7.44v47.977a10.513 10.513 0 003.117 7.439 10.576 10.576 0 007.475 3.061h11.165v17.959l16.746-17.959h47.712a10.573 10.573 0 007.476-3.061 10.516 10.516 0 003.117-7.439V50.937a10.521 10.521 0 00-3.108-7.43 10.567 10.567 0 00-7.458-3.07z'
fill='#1C58D9'
/>
<Path
d='M80.1 109.413h47.712a10.568 10.568 0 007.475-3.061 10.523 10.523 0 003.117-7.439V69.787s-3.331 26.935-3.929 29.306c-.599 2.371-1.787 5.918-7.414 6.506-5.626.588-46.961 3.815-46.961 3.815z'
fill={theme.centerChannelColor}
fillOpacity={0.16}
/>
<Path
d='M64.174 68.066c1.348 0 2.665.399 3.786 1.146a6.787 6.787 0 011.033 10.463 6.82 6.82 0 01-7.427 1.474 6.812 6.812 0 01-3.058-2.504 6.79 6.79 0 01-.632-6.382 6.792 6.792 0 013.689-3.682 6.82 6.82 0 012.61-.515zM90.014 68.066c1.348 0 2.665.399 3.786 1.146a6.804 6.804 0 012.51 3.052 6.787 6.787 0 01-1.477 7.411 6.819 6.819 0 01-7.427 1.474 6.812 6.812 0 01-3.058-2.504 6.79 6.79 0 01-.632-6.382 6.79 6.79 0 013.689-3.682 6.818 6.818 0 012.609-.515zM115.825 68.066a6.825 6.825 0 013.788 1.142 6.802 6.802 0 012.906 6.98 6.802 6.802 0 01-5.352 5.348 6.829 6.829 0 01-6.999-2.89 6.792 6.792 0 01-.633-6.381 6.781 6.781 0 013.683-3.681 6.82 6.82 0 012.607-.518z'
fill={theme.centerChannelBg}
/>
<Path
d='M49.447 60.526a21.376 21.376 0 013.823-7.464 21.424 21.424 0 016.403-5.424.74.74 0 00-.304-1.4c-4.769-.285-14.397.731-11.378 14.217a.748.748 0 00.7.606.752.752 0 00.755-.535z'
fill={theme.centerChannelBg}
fillOpacity={0.16}
/>
<Path
d='M114.364 62.33c-2.475 0-3.597-1.785-2.492-3.966L131.88 19.06c1.133-2.175 2.917-2.175 4.028 0l20.002 39.303c1.133 2.175 0 3.965-2.493 3.965h-39.053z'
fill='#FFBC1F'
/>
<Path
d='M130.753 33.597l2.056 13.816a1.09 1.09 0 001.826.718 1.09 1.09 0 00.344-.718l2.056-13.816c.374-5.387-6.662-5.387-6.282 0zM133.891 49.912a3.148 3.148 0 013.083 3.767 3.153 3.153 0 01-2.476 2.472 3.149 3.149 0 11-.607-6.24z'
fill='#2D3039'
/>
<Ellipse
cx={90.5}
cy={131}
rx={62.5}
ry={3}
fill={theme.centerChannelColor}
fillOpacity={0.06}
/>
</Svg>
);
}
export default SvgComponent;

View file

@ -37,6 +37,7 @@ import type {
type MarkdownProps = {
autolinkedUrlSchemes?: string[];
baseTextStyle: StyleProp<TextStyle>;
baseParagraphStyle?: StyleProp<TextStyle>;
blockStyles?: MarkdownBlockStyles;
channelId?: string;
channelMentions?: ChannelMentions;
@ -131,7 +132,7 @@ const Markdown = ({
enableInlineLatex, enableLatex,
imagesMetadata, isEdited, isReplyPost, isSearchResult, layoutHeight, layoutWidth,
location, mentionKeys, minimumHashtagLength = 3, onPostPress, postId, searchPatterns,
textStyles = {}, theme, value = '',
textStyles = {}, theme, value = '', baseParagraphStyle,
}: MarkdownProps) => {
const style = getStyleSheet(theme);
@ -419,7 +420,7 @@ const Markdown = ({
return (
<View style={blockStyle}>
<Text>
<Text style={baseParagraphStyle}>
{children}
</Text>
</View>

View file

@ -332,7 +332,7 @@ export const queryTeamsById = (database: Database, teamIds: string[]) => {
return database.get<TeamModel>(TEAM).query(Q.where('id', Q.oneOf(teamIds)));
};
export const queryTeamByName = async (database: Database, teamName: string) => {
export const queryTeamByName = (database: Database, teamName: string) => {
return database.get<TeamModel>(TEAM).query(Q.where('name', teamName));
};

View file

@ -7,21 +7,38 @@ import {of as of$} from 'rxjs';
import {switchMap} from 'rxjs/operators';
import {observePost} from '@queries/servers/post';
import {observeCurrentTeamId, observeCurrentUserId} from '@queries/servers/system';
import {queryMyTeamsByIds, queryTeamByName} from '@queries/servers/team';
import {observeIsCRTEnabled} from '@queries/servers/thread';
import {WithDatabaseArgs} from '@typings/database/database';
import PostModel from '@typings/database/models/servers/post';
import Permalink from './permalink';
type OwnProps = {postId: PostModel['id']} & WithDatabaseArgs;
type OwnProps = {
postId: PostModel['id'];
teamName?: string;
} & WithDatabaseArgs;
const enhance = withObservables([], ({database, postId}: OwnProps) => {
const enhance = withObservables([], ({database, postId, teamName}: OwnProps) => {
const post = observePost(database, postId);
const team = teamName ? queryTeamByName(database, teamName).observe().pipe(
switchMap((ts) => {
const t = ts[0];
return t ? t.observe() : of$(undefined);
}),
) : of$(undefined);
return {
channel: post.pipe(
switchMap((p) => (p ? p.channel.observe() : of$(undefined))),
),
isTeamMember: team.pipe(
switchMap((t) => (t ? queryMyTeamsByIds(database, [t.id]).observe() : of$(undefined))),
switchMap((ms) => of$(Boolean(ms?.[0]))),
),
currentTeamId: observeCurrentTeamId(database),
currentUserId: observeCurrentUserId(database),
isCRTEnabled: observeIsCRTEnabled(database),
};
});

View file

@ -2,12 +2,13 @@
// See LICENSE.txt for license information.
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {BackHandler, Text, TouchableOpacity, View} from 'react-native';
import {Alert, BackHandler, Text, TouchableOpacity, View} from 'react-native';
import Animated from 'react-native-reanimated';
import {Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
import {switchToChannelById} from '@actions/remote/channel';
import {fetchPostsAround} from '@actions/remote/post';
import {fetchChannelById, joinChannel, switchToChannelById} from '@actions/remote/channel';
import {fetchPostById, fetchPostsAround} from '@actions/remote/post';
import {addUserToTeam, fetchTeamByName, removeUserFromTeam} from '@actions/remote/team';
import CompassIcon from '@components/compass_icon';
import FormattedText from '@components/formatted_text';
import Loading from '@components/loading';
@ -15,7 +16,9 @@ import PostList from '@components/post_list';
import {Screens} from '@constants';
import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme';
import DatabaseManager from '@database/manager';
import {useIsTablet} from '@hooks/device';
import {getChannelById, getMyChannel} from '@queries/servers/channel';
import {dismissModal} from '@screens/navigation';
import NavigationStore from '@store/navigation_store';
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
@ -24,11 +27,17 @@ import {preventDoubleTap} from '@utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
import PermalinkError from './permalink_error';
import type ChannelModel from '@typings/database/models/servers/channel';
import type PostModel from '@typings/database/models/servers/post';
type Props = {
channel?: ChannelModel;
teamName?: string;
isTeamMember?: boolean;
currentUserId: string;
currentTeamId: string;
isCRTEnabled: boolean;
postId: PostModel['id'];
}
@ -48,6 +57,8 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
flex: 1,
margin: 10,
opacity: 1,
borderWidth: 1,
borderColor: changeOpacity(theme.centerChannelColor, 0.16),
},
header: {
alignItems: 'center',
@ -102,23 +113,18 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
fontWeight: '600',
textAlignVertical: 'center',
},
errorContainer: {
alignItems: 'center',
justifyContent: 'center',
padding: 15,
},
errorText: {
color: changeOpacity(theme.centerChannelColor, 0.4),
fontSize: 15,
},
archiveIcon: {
color: theme.centerChannelColor,
fontSize: 16,
paddingRight: 20,
},
}));
}),
);
function Permalink({channel, isCRTEnabled, postId}: Props) {
function Permalink({
channel,
isCRTEnabled,
postId,
teamName,
isTeamMember,
currentUserId,
currentTeamId,
}: Props) {
const [posts, setPosts] = useState<PostModel[]>([]);
const [loading, setLoading] = useState(true);
const theme = useTheme();
@ -126,6 +132,8 @@ function Permalink({channel, isCRTEnabled, postId}: Props) {
const insets = useSafeAreaInsets();
const isTablet = useIsTablet();
const style = getStyleSheet(theme);
const [error, setError] = useState<PermalinkErrorType>();
const [channelId, setChannelId] = useState(channel?.id);
const containerStyle = useMemo(() => {
const marginTop = isTablet ? 60 : 20;
@ -135,20 +143,113 @@ function Permalink({channel, isCRTEnabled, postId}: Props) {
useEffect(() => {
(async () => {
if (channel?.id) {
const data = await fetchPostsAround(serverUrl, channel.id, postId, 5, isCRTEnabled);
if (channelId) {
const data = await fetchPostsAround(serverUrl, channelId, postId, 5, isCRTEnabled);
if (data.error) {
setError({unreachable: true});
}
if (data?.posts) {
setLoading(false);
setPosts(data.posts);
}
setLoading(false);
return;
}
const database = DatabaseManager.serverDatabases[serverUrl]?.database;
if (!database) {
setError({unreachable: true});
setLoading(false);
return;
}
// If a team is provided, try to join the team, but do not fail here, to take into account:
// - Wrong team name
// - DMs/GMs
let joinedTeam: Team | undefined;
if (teamName && !isTeamMember) {
const fetchData = await fetchTeamByName(serverUrl, teamName, true);
joinedTeam = fetchData.team;
if (joinedTeam) {
const addData = await addUserToTeam(serverUrl, joinedTeam.id, currentUserId);
if (addData.error) {
joinedTeam = undefined;
}
}
}
const {post} = await fetchPostById(serverUrl, postId, true);
if (!post) {
if (joinedTeam) {
removeUserFromTeam(serverUrl, joinedTeam.id, currentUserId);
}
setError({notExist: true});
setLoading(false);
return;
}
const myChannel = await getMyChannel(database, post.channel_id);
if (myChannel) {
const localChannel = await getChannelById(database, myChannel.id);
// Wrong team passed or DM/GM
if (joinedTeam && localChannel?.teamId !== '' && localChannel?.teamId !== joinedTeam.id) {
removeUserFromTeam(serverUrl, joinedTeam.id, currentUserId);
joinedTeam = undefined;
}
if (joinedTeam) {
setError({
joinedTeam: true,
channelId: myChannel.id,
channelName: localChannel?.displayName,
privateTeam: !joinedTeam.allow_open_invite,
teamName: joinedTeam.display_name,
teamId: joinedTeam.id,
});
setLoading(false);
return;
}
setChannelId(post.channel_id);
return;
}
const {channel: fetchedChannel} = await fetchChannelById(serverUrl, post.channel_id);
if (!fetchedChannel) {
if (joinedTeam) {
removeUserFromTeam(serverUrl, joinedTeam.id, currentUserId);
}
setError({notExist: true});
setLoading(false);
return;
}
// Wrong team passed or DM/GM
if (joinedTeam && fetchedChannel.team_id !== '' && fetchedChannel.team_id !== joinedTeam.id) {
removeUserFromTeam(serverUrl, joinedTeam.id, currentUserId);
joinedTeam = undefined;
}
setError({
privateChannel: fetchedChannel.type === 'P',
joinedTeam: Boolean(joinedTeam),
channelId: fetchedChannel.id,
channelName: fetchedChannel.display_name,
teamId: fetchedChannel.team_id || currentTeamId,
teamName: joinedTeam?.display_name,
privateTeam: joinedTeam && !joinedTeam.allow_open_invite,
});
setLoading(false);
})();
}, [channel?.id]);
}, [channelId, teamName]);
const handleClose = useCallback(() => {
if (error?.joinedTeam && error.teamId) {
removeUserFromTeam(serverUrl, error.teamId, currentUserId);
}
dismissModal({componentId: Screens.PERMALINK});
closePermalink();
}, []);
}, [error]);
useEffect(() => {
const listener = BackHandler.addEventListener('hardwareBackPress', () => {
@ -171,6 +272,71 @@ function Permalink({channel, isCRTEnabled, postId}: Props) {
}
}), []);
const handleJoin = useCallback(preventDoubleTap(async () => {
if (error?.teamId && error.channelId) {
const {error: joinError} = await joinChannel(serverUrl, currentUserId, error.teamId, error.channelId);
if (joinError) {
Alert.alert('Error joining the channel', 'There was an error trying to join the channel');
return;
}
setLoading(true);
setError(undefined);
setChannelId(error.channelId);
}
}), [error, serverUrl, currentUserId]);
let content;
if (loading) {
content = (
<View style={style.loading}>
<Loading
color={theme.buttonBg}
/>
</View>
);
} else if (error) {
content = (
<PermalinkError
error={error}
handleClose={handleClose}
handleJoin={handleJoin}
/>
);
} else {
content = (
<>
<View style={style.postList}>
<PostList
highlightedId={postId}
posts={posts}
location={Screens.PERMALINK}
lastViewedAt={0}
shouldShowJoinLeaveMessages={false}
channelId={channel!.id}
testID='permalink.post_list'
nativeID={Screens.PERMALINK}
highlightPinnedOrSaved={false}
/>
</View>
<View style={style.footer}>
<TouchableOpacity
style={[buttonBackgroundStyle(theme, 'lg', 'primary'), {width: '100%'}]}
onPress={handlePress}
testID='permalink.jump_to_recent_messages.button'
>
<FormattedText
testID='permalink.search.jump'
id='mobile.search.jump'
defaultMessage='Jump to recent messages'
style={buttonTextStyle(theme, 'lg', 'primary')}
/>
</TouchableOpacity>
</View>
</>
);
}
const showHeaderDivider = Boolean(channel?.displayName) && !error && !loading;
return (
<SafeAreaView
style={containerStyle}
@ -199,45 +365,12 @@ function Permalink({channel, isCRTEnabled, postId}: Props) {
</Text>
</View>
</View>
{Boolean(channel?.displayName) &&
<View style={style.divider}/>
}
{loading ? (
<View style={style.loading}>
<Loading
color={theme.buttonBg}
/>
</View>
) : (
<View style={style.postList}>
<PostList
highlightedId={postId}
isCRTEnabled={isCRTEnabled}
posts={posts}
location={Screens.PERMALINK}
lastViewedAt={0}
shouldShowJoinLeaveMessages={false}
channelId={channel!.id}
testID='permalink.post_list'
nativeID={Screens.PERMALINK}
highlightPinnedOrSaved={false}
/>
{showHeaderDivider && (
<View style={style.dividerContainer}>
<View style={style.divider}/>
</View>
)}
<View style={style.footer}>
<TouchableOpacity
style={[buttonBackgroundStyle(theme, 'lg', 'primary'), {width: '100%'}]}
onPress={handlePress}
testID='permalink.jump_to_recent_messages.button'
>
<FormattedText
testID='permalink.search.jump'
id='mobile.search.jump'
defaultMessage='Jump to recent messages'
style={buttonTextStyle(theme, 'lg', 'primary')}
/>
</TouchableOpacity>
</View>
{content}
</Animated.View>
</SafeAreaView>
);

View file

@ -0,0 +1,168 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {useIntl} from 'react-intl';
import {Text, TouchableOpacity, View} from 'react-native';
import FormattedText from '@components/formatted_text';
import JoinPrivateChannel from '@components/illustrations/join_private_channel';
import JoinPublicChannel from '@components/illustrations/join_public_channel';
import MessageNotViewable from '@components/illustrations/message_not_viewable';
import Markdown from '@components/markdown';
import {Screens} from '@constants';
import {useTheme} from '@context/theme';
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
type Props = {
error: PermalinkErrorType;
handleClose: () => void;
handleJoin: () => void;
}
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
return {
errorContainer: {
alignItems: 'center',
justifyContent: 'center',
marginHorizontal: 36,
flex: 1,
},
errorTitle: {
color: theme.centerChannelColor,
textAlign: 'center',
...typography('Heading', 600, 'SemiBold'),
marginTop: 8,
marginBottom: 16,
},
errorText: {
textAlign: 'center',
color: theme.centerChannelColor,
...typography('Body', 200, 'Regular'),
},
errorTextParagraph: {
textAlign: 'center',
},
errorButtonContainer: {
borderTopWidth: 1,
borderTopColor: changeOpacity(theme.centerChannelColor, 0.16),
padding: 20,
},
};
});
function PermalinkError({
error,
handleClose,
handleJoin,
}: Props) {
const theme = useTheme();
const style = getStyleSheet(theme);
const intl = useIntl();
const buttonStylePrimary = buttonBackgroundStyle(theme, 'lg', 'primary');
const buttonTextStylePrimary = buttonTextStyle(theme, 'lg', 'primary');
if (error.notExist || error.unreachable) {
const title = intl.formatMessage({id: 'permalink.error.access.title', defaultMessage: 'Message not viewable'});
const text = intl.formatMessage({id: 'permalink.error.access.text', defaultMessage: 'The message you are trying to view is in a channel you dont have access to or has been deleted.'});
return (
<>
<View style={style.errorContainer}>
<MessageNotViewable theme={theme}/>
<Text style={style.errorTitle}>{title}</Text>
<Text style={style.errorText}>{text}</Text>
</View>
<View style={style.errorButtonContainer}>
<TouchableOpacity
style={buttonStylePrimary}
onPress={handleClose}
>
<FormattedText
testID='permalink.error.okay'
id='permalink.error.okay'
defaultMessage='Okay'
style={buttonTextStylePrimary}
/>
</TouchableOpacity>
</View>
</>
);
}
const buttonStyleTertiary = buttonBackgroundStyle(theme, 'lg', 'tertiary');
const buttonTextStyleTertiary = buttonTextStyle(theme, 'lg', 'tertiary');
const isPrivate = error.privateChannel || error.privateTeam;
let image;
let title;
let text;
let button;
if (isPrivate && error.joinedTeam) {
image = (<JoinPrivateChannel theme={theme}/>);
title = intl.formatMessage({id: 'permalink.error.private_channel_and_team.title', defaultMessage: 'Join private channel and team'});
text = intl.formatMessage({id: 'permalink.error.private_channel_and_team.text', defaultMessage: 'The message you are trying to view is in a private channel in a team you are not a member of. You have access as an admin. Do you want to join **{channelName}** and the **{teamName}** team to view it?'}, {channelName: error.channelName, teamName: error.teamName});
button = intl.formatMessage({id: 'permalink.error.private_channel_and_team.button', defaultMessage: 'Join channel and team'});
} else if (isPrivate) {
image = (<JoinPrivateChannel theme={theme}/>);
title = intl.formatMessage({id: 'permalink.error.private_channel.title', defaultMessage: 'Join private channel'});
text = intl.formatMessage({id: 'permalink.error.private_channel.text', defaultMessage: 'The message you are trying to view is in a private channel you have not been invited to, but you have access as an admin. Do you still want to join **{channelName}**?'}, {channelName: error.channelName});
button = intl.formatMessage({id: 'permalink.error.private_channel.button', defaultMessage: 'Join channel'});
} else if (error.joinedTeam) {
image = (<JoinPublicChannel theme={theme}/>);
title = intl.formatMessage({id: 'permalink.error.public_channel_and_team.title', defaultMessage: 'Join channel and team'});
text = intl.formatMessage({id: 'permalink.error.public_channel_and_team.text', defaultMessage: 'The message you are trying to view is in a channel you dont belong and a team you are not a member of. Do you want to join **{channelName}** and the **{teamName}** team to view it?'}, {channelName: error.channelName, teamName: error.teamName});
button = intl.formatMessage({id: 'permalink.error.public_channel_and_team.button', defaultMessage: 'Join channel and team'});
} else {
image = (<JoinPublicChannel theme={theme}/>);
title = intl.formatMessage({id: 'permalink.error.public_channel.title', defaultMessage: 'Join channel'});
text = intl.formatMessage({id: 'permalink.error.public_channel.text', defaultMessage: 'The message you are trying to view is in a channel you dont belong to. Do you want to join **{channelName}** to view it?'}, {channelName: error.channelName});
button = intl.formatMessage({id: 'permalink.error.public_channel.button', defaultMessage: 'Join channel'});
}
return (
<>
<View style={style.errorContainer}>
{image}
<Text style={style.errorTitle}>{title}</Text>
<Markdown
theme={theme}
value={text}
baseTextStyle={style.errorText}
baseParagraphStyle={style.errorTextParagraph}
disableAtMentions={true}
disableAtChannelMentionHighlight={true}
disableChannelLink={true}
disableGallery={true}
disableHashtags={true}
textStyles={getMarkdownTextStyles(theme)}
blockStyles={getMarkdownBlockStyles(theme)}
location={Screens.PERMALINK}
/>
</View>
<View style={style.errorButtonContainer}>
<TouchableOpacity
style={buttonStylePrimary}
onPress={handleJoin}
>
<Text style={buttonTextStylePrimary}>{button}</Text>
</TouchableOpacity>
<TouchableOpacity
style={[buttonStyleTertiary, {marginTop: 8}]}
onPress={handleClose}
>
<FormattedText
testID='permalink.error.cancel'
id='permalink.error.cancel'
defaultMessage='Cancel'
style={buttonTextStyleTertiary}
/>
</TouchableOpacity>
</View>
</>
);
}
export default PermalinkError;

View file

@ -4,6 +4,7 @@
import {Keyboard, Platform} from 'react-native';
import {OptionsModalPresentationStyle} from 'react-native-navigation';
import {Screens} from '@constants';
import {dismissAllModals, showModalOverCurrentContext} from '@screens/navigation';
import {changeOpacity} from '@utils/theme';
@ -15,7 +16,7 @@ export const displayPermalink = async (teamName: string, postId: string, openAsP
await dismissAllModals();
}
const screen = 'Permalink';
const screen = Screens.PERMALINK;
const passProps = {
isPermalink: openAsPermalink,
teamName,

View file

@ -598,6 +598,22 @@
"password_send.link.title": "Reset Link Sent",
"password_send.reset": "Reset Your Password",
"password_send.return": "Return to Log In",
"permalink.error.access.text": "The message you are trying to view is in a channel you dont have access to or has been deleted.",
"permalink.error.access.title": "Message not viewable",
"permalink.error.cancel": "Cancel",
"permalink.error.okay": "Okay",
"permalink.error.private_channel_and_team.button": "Join channel and team",
"permalink.error.private_channel_and_team.text": "The message you are trying to view is in a private channel in a team you are not a member of. You have access as an admin. Do you want to join **{channelName}** and the **{teamName}** team to view it?",
"permalink.error.private_channel_and_team.title": "Join private channel and team",
"permalink.error.private_channel.button": "Join channel",
"permalink.error.private_channel.text": "The message you are trying to view is in a private channel you have not been invited to, but you have access as an admin. Do you still want to join **{channelName}**?",
"permalink.error.private_channel.title": "Join private channel",
"permalink.error.public_channel_and_team.button": "Join channel and team",
"permalink.error.public_channel_and_team.text": "The message you are trying to view is in a channel you dont belong and a team you are not a member of. Do you want to join **{channelName}** and the **{teamName}** team to view it?",
"permalink.error.public_channel_and_team.title": "Join channel and team",
"permalink.error.public_channel.button": "Join channel",
"permalink.error.public_channel.text": "The message you are trying to view is in a channel you dont belong to. Do you want to join **{channelName}** to view it?",
"permalink.error.public_channel.title": "Join channel",
"permalink.show_dialog_warn.cancel": "Cancel",
"permalink.show_dialog_warn.description": "You are about to join {channel} without explicitly being added by the channel admin. Are you sure you wish to join this private channel?",
"permalink.show_dialog_warn.join": "Join",

14
types/components/permalink.d.ts vendored Normal file
View file

@ -0,0 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
type PermalinkErrorType = {
unreachable?: boolean;
notExist?: boolean;
joinedTeam?: boolean;
privateChannel?: boolean;
privateTeam?: boolean;
teamName?: string;
channelName?: string;
teamId?: string;
channelId?: string;
}